done with outgoing sangoma boost sample program
git-svn-id: http://svn.openzap.org/svn/openzap/branches/sangoma_boost@1007 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
parent
0979265548
commit
339e2087bb
|
@ -1,271 +1,70 @@
|
||||||
/*
|
|
||||||
* 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: boostsample <span name>
|
|
||||||
* The span name must be a valid span defined in freetdm.conf
|
|
||||||
* compile this program linking to the freetdm library (ie -lfreetdm)
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include "freetdm.h"
|
#include "freetdm.h"
|
||||||
|
|
||||||
/* arbitrary limit for max calls in this sample program */
|
static FIO_SIGNAL_CB_FUNCTION(on_signal)
|
||||||
#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;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", channel->span_id, channel->chan_id);
|
|
||||||
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_HANGUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send answer for an incoming call */
|
|
||||||
static void send_answer(ftdm_channel_t *channel)
|
|
||||||
{
|
|
||||||
/* we move the channel signaling state machine to UP (answered) */
|
|
||||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", channel->span_id, channel->chan_id);
|
|
||||||
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_UP);
|
|
||||||
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) */
|
|
||||||
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", channel->span_id, channel->chan_id);
|
|
||||||
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_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, "FTDM_SIGEVENT_START 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, "FTDM_SIGEVENT_PROGRESS_MEDIA 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, "FTDM_SIGEVENT_UP received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
|
||||||
break;
|
|
||||||
/* This event signals hangup from the other end */
|
|
||||||
case FTDM_SIGEVENT_STOP:
|
|
||||||
ftdm_log(FTDM_LOG_NOTICE, "FTDM_SIGEVENT_STOP received in channel %d:%d\n", sigmsg->span_id, sigmsg->chan_id);
|
|
||||||
/* release any timer for this channel */
|
|
||||||
release_timers(sigmsg->channel);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return FTDM_FAIL;
|
return FTDM_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int R = 0;
|
||||||
|
#if 0
|
||||||
|
static void handle_SIGINT(int sig)
|
||||||
|
{
|
||||||
|
if (sig);
|
||||||
|
R = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
ftdm_conf_parameter_t parameters[20];
|
ftdm_conf_parameter_t parameters[20];
|
||||||
ftdm_span_t *span;
|
ftdm_span_t *span;
|
||||||
|
int local_port, remote_port;
|
||||||
|
|
||||||
|
local_port = remote_port = 53000;
|
||||||
|
|
||||||
|
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
|
||||||
|
#if 0
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: boostsample <span name>\n");
|
printf("invalid arguments\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* Initialize the FTDM library */
|
|
||||||
if (ftdm_global_init() != FTDM_SUCCESS) {
|
if (ftdm_global_init() != FTDM_SUCCESS) {
|
||||||
fprintf(stderr, "Error loading FreeTDM\n");
|
fprintf(stderr, "Error loading FreeTDM\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create the schedule mutex */
|
|
||||||
ftdm_mutex_create(&g_schedule_mutex);
|
|
||||||
|
|
||||||
/* Load the FreeTDM configuration */
|
|
||||||
if (ftdm_global_configuration() != FTDM_SUCCESS) {
|
if (ftdm_global_configuration() != FTDM_SUCCESS) {
|
||||||
fprintf(stderr, "Error configuring FreeTDM\n");
|
fprintf(stderr, "Error configuring FreeTDM\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* At this point FreeTDM is ready to be used, the spans defined in freetdm.conf have the basic I/O board configuration
|
printf("FreeTDM loaded\n");
|
||||||
* but no telephony signaling configuration at all. */
|
|
||||||
printf("FreeTDM loaded ...\n");
|
|
||||||
|
|
||||||
/* Retrieve a span by name (according to freetdm.conf) */
|
if (ftdm_span_find_by_name("wp1", &span) != FTDM_SUCCESS) {
|
||||||
if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
|
|
||||||
fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
|
fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
|
||||||
goto done;
|
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].var = "sigmod";
|
||||||
parameters[0].val = "sangoma_prid";
|
parameters[0].val = "sangoma_prid";
|
||||||
|
|
||||||
/* following parameters are signaling stack specific, this ones are for PRI */
|
|
||||||
parameters[1].var = "switchtype";
|
parameters[1].var = "switchtype";
|
||||||
parameters[1].val = "euroisdn";
|
parameters[1].val = "euroisdn";
|
||||||
|
parameters[1].var = "signalling";
|
||||||
parameters[2].var = "signalling";
|
parameters[1].val = "pri_cpe";
|
||||||
parameters[2].val = "pri_cpe";
|
parameters[2].var = NULL;
|
||||||
|
if (ftdm_configure_span_signaling("sangoma_boost", span, on_signal, parameters) == FTDM_SUCCESS) {
|
||||||
/* the last parameter .var member must be NULL! */
|
ftdm_span_start(span);
|
||||||
parameters[3].var = NULL;
|
} else {
|
||||||
|
fprintf(stderr, "Error starting SS7_BOOST\n");
|
||||||
/* send the configuration values down to the stack */
|
|
||||||
if (ftdm_configure_span_signaling("sangoma_boost", span, on_signaling_event, parameters) != FTDM_SUCCESS) {
|
|
||||||
fprintf(stderr, "Error configuring sangoma_boost signaling abstraction in span %s\n", span->name);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* configuration succeeded, we can proceed now to start the span
|
while(ftdm_running() && R) {
|
||||||
* 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.
|
|
||||||
* */
|
|
||||||
ftdm_span_start(span);
|
|
||||||
|
|
||||||
app_running = 1;
|
|
||||||
|
|
||||||
/* The application thread can go on and do anything else, like waiting for a shutdown signal */
|
|
||||||
while(ftdm_running() && app_running) {
|
|
||||||
ftdm_sleep(1 * 1000);
|
ftdm_sleep(1 * 1000);
|
||||||
run_timers();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
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();
|
ftdm_global_destroy();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,73 +1,285 @@
|
||||||
|
/*
|
||||||
|
* 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: boostsample <span name>
|
||||||
|
* The span name must be a valid span defined in freetdm.conf
|
||||||
|
* compile this program linking to the freetdm library (ie -lfreetdm)
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "freetdm.h"
|
#include "freetdm.h"
|
||||||
|
|
||||||
static FIO_SIGNAL_CB_FUNCTION(on_signal)
|
/* 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;
|
||||||
|
|
||||||
|
static void interrupt_requested(int signal)
|
||||||
{
|
{
|
||||||
return FTDM_FAIL;
|
app_running = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int R = 0;
|
static void schedule_timer(ftdm_channel_t *channel, int sec, expired_function_t expired)
|
||||||
#if 0
|
|
||||||
static void handle_SIGINT(int sig)
|
|
||||||
{
|
{
|
||||||
if (sig);
|
int i;
|
||||||
R = 0;
|
ftdm_mutex_lock(g_schedule_mutex);
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting hangup in channel %d:%d\n", channel->span_id, channel->chan_id);
|
||||||
|
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_HANGUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send answer for an incoming call */
|
||||||
|
static void send_answer(ftdm_channel_t *channel)
|
||||||
|
{
|
||||||
|
/* we move the channel signaling state machine to UP (answered) */
|
||||||
|
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting answer in channel %d:%d\n", channel->span_id, channel->chan_id);
|
||||||
|
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_UP);
|
||||||
|
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) */
|
||||||
|
ftdm_log(FTDM_LOG_NOTICE, "-- Requesting progress\n", channel->span_id, channel->chan_id);
|
||||||
|
ftdm_set_state_locked(channel, FTDM_CHANNEL_STATE_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);
|
||||||
|
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);
|
||||||
|
/* release any timer for this channel */
|
||||||
|
release_timers(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;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
ftdm_conf_parameter_t parameters[20];
|
||||||
ftdm_span_t *span;
|
ftdm_span_t *span;
|
||||||
int local_port, remote_port;
|
|
||||||
|
|
||||||
local_port = remote_port = 53000;
|
|
||||||
|
|
||||||
ftdm_global_set_default_logger(FTDM_LOG_LEVEL_DEBUG);
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("umm no\n");
|
fprintf(stderr, "Usage: %s <span name>\n", argv[0]);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (signal(SIGINT, interrupt_requested) == SIG_ERR) {
|
||||||
|
fprintf(stderr, "Could not set the SIGINT signal handler: %s\n", strerror(errno));
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Initialize the FTDM library */
|
||||||
if (ftdm_global_init() != FTDM_SUCCESS) {
|
if (ftdm_global_init() != FTDM_SUCCESS) {
|
||||||
fprintf(stderr, "Error loading FreeTDM\n");
|
fprintf(stderr, "Error loading FreeTDM\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create the schedule mutex */
|
||||||
|
ftdm_mutex_create(&g_schedule_mutex);
|
||||||
|
|
||||||
|
/* Load the FreeTDM configuration */
|
||||||
if (ftdm_global_configuration() != FTDM_SUCCESS) {
|
if (ftdm_global_configuration() != FTDM_SUCCESS) {
|
||||||
fprintf(stderr, "Error configuring FreeTDM\n");
|
fprintf(stderr, "Error configuring FreeTDM\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("FreeTDM loaded\n");
|
/* 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. */
|
||||||
|
printf("FreeTDM loaded ...\n");
|
||||||
|
|
||||||
if (ftdm_span_find(atoi(argv[1]), &span) != FTDM_SUCCESS) {
|
/* Retrieve a span by name (according to freetdm.conf) */
|
||||||
fprintf(stderr, "Error finding FreeTDM span\n");
|
if (ftdm_span_find_by_name(argv[1], &span) != FTDM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error finding FreeTDM span %s\n", argv[1]);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
/* prepare the configuration parameters that will be sent down to the signaling stack, the array of paramters must be terminated by an
|
||||||
if (1) {
|
* array element with a null .var member */
|
||||||
if (ftdm_configure_span("sangoma_boost", span, on_signal,
|
|
||||||
"sigmod", "sangoma_brid",
|
|
||||||
"local_port", &local_port,
|
|
||||||
"remote_ip", "127.0.0.66",
|
|
||||||
"remote_port", &remote_port,
|
|
||||||
TAG_END) == FTDM_SUCCESS) {
|
|
||||||
ftdm_span_start(span);
|
|
||||||
|
|
||||||
} else {
|
/* for sangoma_boost signaling (abstraction signaling used by Sangoma for PRI, BRI and SS7) the first parameter you must send
|
||||||
fprintf(stderr, "Error starting sangoma_boost\n");
|
* is sigmod, which must be either sangoma_prid, if you have the PRI stack available, or sangoma_brid for the BRI stack */
|
||||||
goto done;
|
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";
|
||||||
|
|
||||||
|
/* 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("sangoma_boost", span, on_signaling_event, parameters) != FTDM_SUCCESS) {
|
||||||
|
fprintf(stderr, "Error configuring sangoma_boost signaling abstraction in span %s\n", span->name);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
while(ftdm_running() && R) {
|
/* configuration succeeded, we can proceed now to start the 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.
|
||||||
|
* */
|
||||||
|
ftdm_span_start(span);
|
||||||
|
|
||||||
|
app_running = 1;
|
||||||
|
|
||||||
|
/* The application thread can go on and do anything else, like waiting for a shutdown signal */
|
||||||
|
while(ftdm_running() && app_running) {
|
||||||
ftdm_sleep(1 * 1000);
|
ftdm_sleep(1 * 1000);
|
||||||
|
run_timers();
|
||||||
}
|
}
|
||||||
|
printf("Shutting down FreeTDM ...\n");
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
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();
|
ftdm_global_destroy();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue