diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h new file mode 100644 index 0000000000..95b15d358c --- /dev/null +++ b/libs/freetdm/src/include/freetdm.h @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * 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. + * + * Contributors: + * + * Moises Silva + * + */ + +#ifndef OPENFTDM_H +#define OPENFTDM_H + + +#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) +#define _XOPEN_SOURCE 600 +#endif + +#ifndef HAVE_STRINGS_H +#define HAVE_STRINGS_H 1 +#endif +#ifndef HAVE_SYS_SOCKET_H +#define HAVE_SYS_SOCKET_H 1 +#endif + +#ifndef __WINDOWS__ +#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) +#define __WINDOWS__ +#endif +#endif + +#ifdef _MSC_VER +#if defined(FT_DECLARE_STATIC) +#define FT_DECLARE(type) type __stdcall +#define FT_DECLARE_NONSTD(type) type __cdecl +#define FT_DECLARE_DATA +#elif defined(OPENFTDM_EXPORTS) +#define FT_DECLARE(type) __declspec(dllexport) type __stdcall +#define FT_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define FT_DECLARE_DATA __declspec(dllexport) +#else +#define FT_DECLARE(type) __declspec(dllimport) type __stdcall +#define FT_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define FT_DECLARE_DATA __declspec(dllimport) +#endif +#define EX_DECLARE_DATA __declspec(dllexport) +#else +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(HAVE_VISIBILITY) +#define FT_DECLARE(type) __attribute__((visibility("default"))) type +#define FT_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type +#define FT_DECLARE_DATA __attribute__((visibility("default"))) +#else +#define FT_DECLARE(type) type +#define FT_DECLARE_NONSTD(type) type +#define FT_DECLARE_DATA +#endif +#define EX_DECLARE_DATA +#endif + +#ifdef _MSC_VER +#ifndef __inline__ +#define __inline__ __inline +#endif +#if (_MSC_VER >= 1400) /* VC8+ */ +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif +#endif +#ifndef strcasecmp +#define strcasecmp(s1, s2) _stricmp(s1, s2) +#endif +#ifndef strncasecmp +#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) +#endif +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef S_IRUSR +#define S_IRUSR _S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR _S_IWRITE +#endif +#undef HAVE_STRINGS_H +#undef HAVE_SYS_SOCKET_H +/* disable warning for zero length array in a struct */ +/* this will cause errors on c99 and ansi compliant compilers and will need to be fixed in the wanpipe header files */ +#pragma warning(disable:4706) +#pragma comment(lib, "Winmm") +#endif + +#define FTDM_THREAD_STACKSIZE 240 * 1024 +#define FTDM_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL }; +#define FTDM_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) FT_DECLARE(_TYPE) _FUNC1 (const char *name); FT_DECLARE(const char *) _FUNC2 (_TYPE type); +#define FTDM_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \ + FT_DECLARE(_TYPE) _FUNC1 (const char *name) \ + { \ + int i; \ + _TYPE t = _MAX ; \ + \ + for (i = 0; i < _MAX ; i++) { \ + if (!strcasecmp(name, _STRINGS[i])) { \ + t = (_TYPE) i; \ + break; \ + } \ + } \ + \ + return t; \ + } \ + FT_DECLARE(const char *) _FUNC2 (_TYPE type) \ + { \ + if (type > _MAX) { \ + type = _MAX; \ + } \ + return _STRINGS[(int)type]; \ + } \ + +#define ftdm_true(expr) \ + (expr && ( !strcasecmp(expr, "yes") || \ + !strcasecmp(expr, "on") || \ + !strcasecmp(expr, "true") || \ + !strcasecmp(expr, "enabled") || \ + !strcasecmp(expr, "active") || \ + atoi(expr))) ? 1 : 0 + + +#include +#ifndef __WINDOWS__ +#include +#endif + +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include "ftdm_types.h" +#include "hashtable.h" +#include "ftdm_config.h" +#include "g711.h" +#include "libteletone.h" +#include "ftdm_buffer.h" +#include "ftdm_threadmutex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __WINDOWS__ +#define ftdm_sleep(x) Sleep(x) +#else +#define ftdm_sleep(x) usleep(x * 1000) +#endif + +#ifdef NDEBUG +#undef assert +#define assert(_Expression) ((void)(_Expression)) +#endif + +#define FTDM_MAX_CHANNELS_PHYSICAL_SPAN 32 +#define FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN 32 +#define FTDM_MAX_CHANNELS_SPAN FTDM_MAX_CHANNELS_PHYSICAL_SPAN * FTDM_MAX_PHYSICAL_SPANS_PER_LOGICAL_SPAN +#define FTDM_MAX_SPANS_INTERFACE 128 + +#define FTDM_MAX_CHANNELS_GROUP 1024 +#define FTDM_MAX_GROUPS_INTERFACE FTDM_MAX_SPANS_INTERFACE + +#define GOTO_STATUS(label,st) status = st; goto label ; + +#define ftdm_copy_string(x,y,z) strncpy(x, y, z - 1) +#define ftdm_set_string(x,y) strncpy(x, y, sizeof(x)-1) +#define ftdm_strlen_zero(s) (!s || *s == '\0') +#define ftdm_strlen_zero_buf(s) (*s == '\0') + + +#define ftdm_channel_test_feature(obj, flag) ((obj)->features & flag) +#define ftdm_channel_set_feature(obj, flag) (obj)->features |= (flag) +#define ftdm_channel_clear_feature(obj, flag) (obj)->features &= ~(flag) +#define ftdm_channel_set_member_locked(obj, _m, _v) ftdm_mutex_lock(obj->mutex); obj->_m = _v; ftdm_mutex_unlock(obj->mutex) + +/*! + \brief Test for the existance of a flag on an arbitary object + \command obj the object to test + \command flag the or'd list of flags to test + \return true value if the object has the flags defined +*/ +#define ftdm_test_flag(obj, flag) ((obj)->flags & flag) +#define ftdm_test_pflag(obj, flag) ((obj)->pflags & flag) +#define ftdm_test_sflag(obj, flag) ((obj)->sflags & flag) + + +#define ftdm_set_alarm_flag(obj, flag) (obj)->alarm_flags |= (flag) +#define ftdm_clear_alarm_flag(obj, flag) (obj)->alarm_flags &= ~(flag) +#define ftdm_test_alarm_flag(obj, flag) ((obj)->alarm_flags & flag) + +/*! + \brief Set a flag on an arbitrary object + \command obj the object to set the flags on + \command flag the or'd list of flags to set +*/ +#define ftdm_set_flag(obj, flag) (obj)->flags |= (flag) +#define ftdm_set_flag_locked(obj, flag) assert(obj->mutex != NULL); \ + ftdm_mutex_lock(obj->mutex); \ + (obj)->flags |= (flag); \ + ftdm_mutex_unlock(obj->mutex); + +#define ftdm_set_pflag(obj, flag) (obj)->pflags |= (flag) +#define ftdm_set_pflag_locked(obj, flag) assert(obj->mutex != NULL); \ + ftdm_mutex_lock(obj->mutex); \ + (obj)->pflags |= (flag); \ + ftdm_mutex_unlock(obj->mutex); + +#define ftdm_set_sflag(obj, flag) (obj)->sflags |= (flag) +#define ftdm_set_sflag_locked(obj, flag) assert(obj->mutex != NULL); \ + ftdm_mutex_lock(obj->mutex); \ + (obj)->sflags |= (flag); \ + ftdm_mutex_unlock(obj->mutex); + +/*! + \brief Clear a flag on an arbitrary object while locked + \command obj the object to test + \command flag the or'd list of flags to clear +*/ +#define ftdm_clear_flag(obj, flag) (obj)->flags &= ~(flag) + +#define ftdm_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); ftdm_mutex_unlock(obj->mutex); + +#define ftdm_clear_pflag(obj, flag) (obj)->pflags &= ~(flag) + +#define ftdm_clear_pflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->pflags &= ~(flag); ftdm_mutex_unlock(obj->mutex); + +#define ftdm_clear_sflag(obj, flag) (obj)->sflags &= ~(flag) + +#define ftdm_clear_sflag_locked(obj, flag) assert(obj->mutex != NULL); ftdm_mutex_lock(obj->mutex); (obj)->sflags &= ~(flag); ftdm_mutex_unlock(obj->mutex); + + +#define ftdm_set_state_locked(obj, s) if ( obj->state == s ) { \ + ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); \ + } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \ + ftdm_channel_state_t st = obj->state; \ + ftdm_channel_set_state(obj, s, 1); \ + if (obj->state == s) ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \ + else ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); \ + } + +#ifdef _MSC_VER +/* The while(0) below throws a conditional expression is constant warning */ +#pragma warning(disable:4127) +#endif + +#define ftdm_set_state_locked_wait(obj, s) \ + do { \ + int __safety = 100; \ + ftdm_set_state_locked(obj, s); \ + while(__safety-- && ftdm_test_flag(obj, FTDM_CHANNEL_STATE_CHANGE)) { \ + ftdm_sleep(10); \ + } \ + if(!__safety) { \ + ftdm_log(FTDM_LOG_CRIT, "State change not completed\n"); \ + } \ + } while(0); + +#define ftdm_wait_for_flag_cleared(obj, flag, time) \ + do { \ + int __safety = time; \ + while(__safety-- && ftdm_test_flag(obj, flag)) { \ + ftdm_mutex_unlock(obj->mutex); \ + ftdm_sleep(10); \ + ftdm_mutex_lock(obj->mutex); \ + } \ + if(!__safety) { \ + ftdm_log(FTDM_LOG_CRIT, "flag %d was never cleared\n", flag); \ + } \ + } while(0); + +#define ftdm_set_state_wait(obj, s) \ + do { \ + ftdm_channel_set_state(obj, s, 0); \ + ftdm_wait_for_flag_cleared(obj, FTDM_CHANNEL_STATE_CHANGE, 100); \ + } while(0); + + +typedef enum { + FTDM_STATE_CHANGE_FAIL, + FTDM_STATE_CHANGE_SUCCESS, + FTDM_STATE_CHANGE_SAME, +} ftdm_state_change_result_t; + +#define ftdm_set_state_r(obj, s, l, r) if ( obj->state == s ) { \ + ftdm_log(FTDM_LOG_WARNING, "Why bother changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(obj->state), ftdm_channel_state2str(s)); r = FTDM_STATE_CHANGE_SAME; \ + } else if (ftdm_test_flag(obj, FTDM_CHANNEL_READY)) { \ + int st = obj->state; \ + r = (ftdm_channel_set_state(obj, s, l) == FTDM_SUCCESS) ? FTDM_STATE_CHANGE_SUCCESS : FTDM_STATE_CHANGE_FAIL; \ + if (obj->state == s) {ftdm_log(FTDM_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s));} \ + else {ftdm_log(FTDM_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, ftdm_channel_state2str(st), ftdm_channel_state2str(s)); } \ + } + + +#define ftdm_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119) + +/*! + \brief Copy flags from one arbitrary object to another + \command dest the object to copy the flags to + \command src the object to copy the flags from + \command flags the flags to copy +*/ +#define ftdm_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags)) + +struct ftdm_stream_handle { + ftdm_stream_handle_write_function_t write_function; + ftdm_stream_handle_raw_write_function_t raw_write_function; + void *data; + void *end; + ftdm_size_t data_size; + ftdm_size_t data_len; + ftdm_size_t alloc_len; + ftdm_size_t alloc_chunk; +}; + + +FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_raw_write(ftdm_stream_handle_t *handle, uint8_t *data, ftdm_size_t datalen); +FT_DECLARE_NONSTD(ftdm_status_t) ftdm_console_stream_write(ftdm_stream_handle_t *handle, const char *fmt, ...); + +#define FTDM_CMD_CHUNK_LEN 1024 +#define FTDM_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(FTDM_CMD_CHUNK_LEN); \ + assert(s.data); \ + memset(s.data, 0, FTDM_CMD_CHUNK_LEN); \ + s.end = s.data; \ + s.data_size = FTDM_CMD_CHUNK_LEN; \ + s.write_function = ftdm_console_stream_write; \ + s.raw_write_function = ftdm_console_stream_raw_write; \ + s.alloc_len = FTDM_CMD_CHUNK_LEN; \ + s.alloc_chunk = FTDM_CMD_CHUNK_LEN + +struct ftdm_event { + ftdm_event_type_t e_type; + uint32_t enum_id; + ftdm_channel_t *channel; + void *data; +}; + +#define FTDM_TOKEN_STRLEN 128 +#define FTDM_MAX_TOKENS 10 + +static __inline__ char *ftdm_clean_string(char *s) +{ + char *p; + + for (p = s; p && *p; p++) { + uint8_t x = (uint8_t) *p; + if (x < 32 || x > 127) { + *p = ' '; + } + } + + return s; +} + +struct ftdm_bitstream { + uint8_t *data; + uint32_t datalen; + uint32_t byte_index; + uint8_t bit_index; + int8_t endian; + uint8_t top; + uint8_t bot; + uint8_t ss; + uint8_t ssv; +}; + +struct ftdm_fsk_data_state { + dsp_fsk_handle_t *fsk1200_handle; + uint8_t init; + uint8_t *buf; + size_t bufsize; + ftdm_size_t blen; + ftdm_size_t bpos; + ftdm_size_t dlen; + ftdm_size_t ppos; + int checksum; +}; + +struct ftdm_fsk_modulator { + teletone_dds_state_t dds; + ftdm_bitstream_t bs; + uint32_t carrier_bits_start; + uint32_t carrier_bits_stop; + uint32_t chan_sieze_bits; + uint32_t bit_factor; + uint32_t bit_accum; + uint32_t sample_counter; + int32_t samples_per_bit; + int32_t est_bytes; + fsk_modem_types_t modem_type; + ftdm_fsk_data_state_t *fsk_data; + ftdm_fsk_write_sample_t write_sample_callback; + void *user_data; + int16_t sample_buffer[64]; +}; + +/** + * Type Of Number (TON) + */ +typedef enum { + FTDM_TON_UNKNOWN = 0, + FTDM_TON_INTERNATIONAL, + FTDM_TON_NATIONAL, + FTDM_TON_NETWORK_SPECIFIC, + FTDM_TON_SUBSCRIBER_NUMBER, + FTDM_TON_ABBREVIATED_NUMBER, + FTDM_TON_RESERVED +} ftdm_ton_t; + +typedef struct { + char digits[25]; + uint8_t type; + uint8_t plan; +} ftdm_number_t; + +typedef enum { + FTDM_CALLER_STATE_DIALING, + FTDM_CALLER_STATE_SUCCESS, + FTDM_CALLER_STATE_FAIL +} ftdm_caller_state_t; + +struct ftdm_caller_data { + char cid_date[8]; + char cid_name[80]; + ftdm_number_t cid_num; + ftdm_number_t ani; + ftdm_number_t dnis; + ftdm_number_t rdnis; + char aniII[25]; + uint8_t screen; + uint8_t pres; + char collected[25]; + int CRV; + int hangup_cause; + uint8_t raw_data[1024]; + uint32_t raw_data_len; + uint32_t flags; + ftdm_caller_state_t call_state; + uint32_t chan_id; +}; + +typedef enum { + FTDM_TYPE_NONE, + FTDM_TYPE_SPAN = 0xFF, + FTDM_TYPE_CHANNEL +} ftdm_data_type_t; + +/* 2^8 table size, one for each byte value */ +#define FTDM_GAINS_TABLE_SIZE 256 +struct ftdm_channel { + ftdm_data_type_t data_type; + uint32_t span_id; + uint32_t chan_id; + uint32_t physical_span_id; + uint32_t physical_chan_id; + uint32_t rate; + uint32_t extra_id; + ftdm_chan_type_t type; + ftdm_socket_t sockfd; + ftdm_channel_flag_t flags; + uint32_t pflags; + uint32_t sflags; + ftdm_alarm_flag_t alarm_flags; + ftdm_channel_feature_t features; + ftdm_codec_t effective_codec; + ftdm_codec_t native_codec; + uint32_t effective_interval; + uint32_t native_interval; + uint32_t packet_len; + ftdm_channel_state_t state; + ftdm_channel_state_t last_state; + ftdm_channel_state_t init_state; + ftdm_mutex_t *mutex; + teletone_dtmf_detect_state_t dtmf_detect; + uint32_t buffer_delay; + ftdm_event_t event_header; + char last_error[256]; + zio_event_cb_t event_callback; + uint32_t skip_read_frames; + ftdm_buffer_t *dtmf_buffer; + ftdm_buffer_t *gen_dtmf_buffer; + ftdm_buffer_t *pre_buffer; + ftdm_buffer_t *digit_buffer; + ftdm_buffer_t *fsk_buffer; + ftdm_mutex_t *pre_buffer_mutex; + uint32_t dtmf_on; + uint32_t dtmf_off; + char *dtmf_hangup_buf; + teletone_generation_session_t tone_session; + ftdm_time_t last_event_time; + ftdm_time_t ring_time; + char tokens[FTDM_MAX_TOKENS+1][FTDM_TOKEN_STRLEN]; + uint8_t needed_tones[FTDM_TONEMAP_INVALID]; + uint8_t detected_tones[FTDM_TONEMAP_INVALID]; + ftdm_tonemap_t last_detected_tone; + uint32_t token_count; + char chan_name[128]; + char chan_number[32]; + ftdm_filehandle_t fds[2]; + ftdm_fsk_data_state_t fsk; + uint8_t fsk_buf[80]; + uint32_t ring_count; + void *mod_data; + void *call_data; + struct ftdm_caller_data caller_data; + struct ftdm_span *span; + struct ftdm_io_interface *zio; + ftdm_hash_t *variable_hash; + unsigned char rx_cas_bits; + uint32_t pre_buffer_size; + unsigned char rxgain_table[FTDM_GAINS_TABLE_SIZE]; + unsigned char txgain_table[FTDM_GAINS_TABLE_SIZE]; + float rxgain; + float txgain; +}; + + +struct ftdm_sigmsg { + ftdm_signal_event_t event_id; + uint32_t chan_id; + uint32_t span_id; + ftdm_channel_t *channel; + void *raw_data; + uint32_t raw_data_len; +}; + + +struct ftdm_span { + ftdm_data_type_t data_type; + char *name; + uint32_t span_id; + uint32_t chan_count; + ftdm_span_flag_t flags; + struct ftdm_io_interface *zio; + zio_event_cb_t event_callback; + ftdm_mutex_t *mutex; + ftdm_trunk_type_t trunk_type; + ftdm_analog_start_type_t start_type; + ftdm_signal_type_t signal_type; + void *signal_data; + ftdm_event_t event_header; + char last_error[256]; + char tone_map[FTDM_TONEMAP_INVALID+1][FTDM_TONEMAP_LEN]; + teletone_tone_map_t tone_detect_map[FTDM_TONEMAP_INVALID+1]; + teletone_multi_tone_t tone_finder[FTDM_TONEMAP_INVALID+1]; + ftdm_channel_t *channels[FTDM_MAX_CHANNELS_SPAN+1]; + zio_channel_outgoing_call_t outgoing_call; + zio_channel_set_sig_status_t set_channel_sig_status; + zio_channel_get_sig_status_t get_channel_sig_status; + zio_span_set_sig_status_t set_span_sig_status; + zio_span_get_sig_status_t get_span_sig_status; + zio_channel_request_t channel_request; + ftdm_span_start_t start; + ftdm_span_stop_t stop; + void *mod_data; + char *type; + char *dtmf_hangup; + size_t dtmf_hangup_len; + int suggest_chan_id; + ftdm_state_map_t *state_map; + struct ftdm_span *next; +}; + +struct ftdm_group { + char *name; + uint32_t group_id; + uint32_t chan_count; + ftdm_channel_t *channels[FTDM_MAX_CHANNELS_GROUP]; + uint32_t last_used_index; + ftdm_mutex_t *mutex; + struct ftdm_group *next; +}; + +FT_DECLARE_DATA extern ftdm_logger_t ftdm_log; + +typedef enum { + FTDM_CRASH_NEVER = 0, + FTDM_CRASH_ON_ASSERT +} ftdm_crash_policy_t; + +FT_DECLARE_DATA extern ftdm_crash_policy_t g_ftdm_crash_policy; + +typedef void *(*ftdm_malloc_func_t)(void *pool, ftdm_size_t len); +typedef void *(*ftdm_calloc_func_t)(void *pool, ftdm_size_t elements, ftdm_size_t len); +typedef void (*ftdm_free_func_t)(void *pool, void *ptr); +typedef struct ftdm_memory_handler { + void *pool; + ftdm_malloc_func_t malloc; + ftdm_calloc_func_t calloc; + ftdm_free_func_t free; +} ftdm_memory_handler_t; + +FT_DECLARE_DATA extern ftdm_memory_handler_t g_ftdm_mem_handler; + +struct ftdm_io_interface { + const char *name; + zio_configure_span_t configure_span; + zio_configure_t configure; + zio_open_t open; + zio_close_t close; + zio_channel_destroy_t channel_destroy; + zio_span_destroy_t span_destroy; + zio_get_alarms_t get_alarms; + zio_command_t command; + zio_wait_t wait; + zio_read_t read; + zio_write_t write; + zio_span_poll_event_t poll_event; + zio_span_next_event_t next_event; + zio_api_t api; +}; + +typedef struct ftdm_queue ftdm_queue_t; +typedef ftdm_status_t (*ftdm_queue_create_func_t)(ftdm_queue_t **queue, ftdm_size_t capacity); +typedef ftdm_status_t (*ftdm_queue_enqueue_func_t)(ftdm_queue_t *queue, void *obj); +typedef void *(*ftdm_queue_dequeue_func_t)(ftdm_queue_t *queue); +typedef ftdm_status_t (*ftdm_queue_wait_func_t)(ftdm_queue_t *queue, int ms); +typedef ftdm_status_t (*ftdm_queue_destroy_func_t)(ftdm_queue_t **queue); +typedef struct ftdm_queue_handler { + ftdm_queue_create_func_t create; + ftdm_queue_enqueue_func_t enqueue; + ftdm_queue_dequeue_func_t dequeue; + ftdm_queue_wait_func_t wait; + ftdm_queue_destroy_func_t destroy; +} ftdm_queue_handler_t; +FT_DECLARE_DATA extern ftdm_queue_handler_t g_ftdm_queue_handler; + +/*! brief create a new queue */ +#define ftdm_queue_create(queue, capacity) g_ftdm_queue_handler.create(queue, capacity) + +/*! Enqueue an object */ +#define ftdm_queue_enqueue(queue, obj) g_ftdm_queue_handler.enqueue(queue, obj) + +/*! dequeue an object from the queue */ +#define ftdm_queue_dequeue(queue) g_ftdm_queue_handler.dequeue(queue) + +/*! wait ms milliseconds for a queue to have available objects, -1 to wait forever */ +#define ftdm_queue_wait(queue, ms) g_ftdm_queue_handler.wait(queue, ms) + +/*! destroy the queue */ +#define ftdm_queue_destroy(queue) g_ftdm_queue_handler.destroy(queue) + +/*! \brief Override the default queue handler */ +FT_DECLARE(ftdm_status_t) ftdm_global_set_queue_handler(ftdm_queue_handler_t *handler); + +/*! \brief Duplicate string */ +FT_DECLARE(char *) ftdm_strdup(const char *str); +FT_DECLARE(char *) ftdm_strndup(const char *str, ftdm_size_t inlen); + +FT_DECLARE(ftdm_size_t) ftdm_fsk_modulator_generate_bit(ftdm_fsk_modulator_t *fsk_trans, int8_t bit, int16_t *buf, ftdm_size_t buflen); +FT_DECLARE(int32_t) ftdm_fsk_modulator_generate_carrier_bits(ftdm_fsk_modulator_t *fsk_trans, uint32_t bits); +FT_DECLARE(void) ftdm_fsk_modulator_generate_chan_sieze(ftdm_fsk_modulator_t *fsk_trans); +FT_DECLARE(void) ftdm_fsk_modulator_send_data(ftdm_fsk_modulator_t *fsk_trans); +#define ftdm_fsk_modulator_send_all(_it) ftdm_fsk_modulator_generate_chan_sieze(_it); \ + ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \ + ftdm_fsk_modulator_send_data(_it); \ + ftdm_fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop) + +FT_DECLARE(ftdm_status_t) ftdm_fsk_modulator_init(ftdm_fsk_modulator_t *fsk_trans, + fsk_modem_types_t modem_type, + uint32_t sample_rate, + ftdm_fsk_data_state_t *fsk_data, + float db_level, + uint32_t carrier_bits_start, + uint32_t carrier_bits_stop, + uint32_t chan_sieze_bits, + ftdm_fsk_write_sample_t write_sample_callback, + void *user_data); +FT_DECLARE(int8_t) ftdm_bitstream_get_bit(ftdm_bitstream_t *bsp); +FT_DECLARE(void) ftdm_bitstream_init(ftdm_bitstream_t *bsp, uint8_t *data, uint32_t datalen, ftdm_endian_t endian, uint8_t ss); +FT_DECLARE(ftdm_status_t) ftdm_fsk_data_parse(ftdm_fsk_data_state_t *state, ftdm_size_t *type, char **data, ftdm_size_t *len); +FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_feed(ftdm_fsk_data_state_t *state, int16_t *data, size_t samples); +FT_DECLARE(ftdm_status_t) ftdm_fsk_demod_destroy(ftdm_fsk_data_state_t *state); +FT_DECLARE(int) ftdm_fsk_demod_init(ftdm_fsk_data_state_t *state, int rate, uint8_t *buf, size_t bufsize); +FT_DECLARE(ftdm_status_t) ftdm_fsk_data_init(ftdm_fsk_data_state_t *state, uint8_t *data, uint32_t datalen); +FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_mdmf(ftdm_fsk_data_state_t *state, ftdm_mdmf_type_t type, const uint8_t *data, uint32_t datalen); +FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_checksum(ftdm_fsk_data_state_t *state); +FT_DECLARE(ftdm_status_t) ftdm_fsk_data_add_sdmf(ftdm_fsk_data_state_t *state, const char *date, char *number); +FT_DECLARE(ftdm_status_t) ftdm_channel_outgoing_call(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_set_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status); +FT_DECLARE(ftdm_status_t) ftdm_channel_get_sig_status(ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status); +FT_DECLARE(ftdm_status_t) ftdm_span_set_sig_status(ftdm_span_t *span, ftdm_signaling_status_t status); +FT_DECLARE(ftdm_status_t) ftdm_span_get_sig_status(ftdm_span_t *span, ftdm_signaling_status_t *status); +FT_DECLARE(void) ftdm_channel_rotate_tokens(ftdm_channel_t *ftdmchan); +FT_DECLARE(void) ftdm_channel_clear_detected_tones(ftdm_channel_t *ftdmchan); +FT_DECLARE(void) ftdm_channel_clear_needed_tones(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_get_alarms(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_send_fsk_data(ftdm_channel_t *ftdmchan, ftdm_fsk_data_state_t *fsk_data, float db_level); +FT_DECLARE(ftdm_status_t) ftdm_channel_clear_token(ftdm_channel_t *ftdmchan, const char *token); +FT_DECLARE(void) ftdm_channel_replace_token(ftdm_channel_t *ftdmchan, const char *old_token, const char *new_token); +FT_DECLARE(ftdm_status_t) ftdm_channel_add_token(ftdm_channel_t *ftdmchan, char *token, int end); +FT_DECLARE(ftdm_status_t) ftdm_channel_set_state(ftdm_channel_t *ftdmchan, ftdm_channel_state_t state, int lock); +FT_DECLARE(ftdm_status_t) ftdm_span_load_tones(ftdm_span_t *span, const char *mapname); +FT_DECLARE(ftdm_size_t) ftdm_channel_dequeue_dtmf(ftdm_channel_t *ftdmchan, char *dtmf, ftdm_size_t len); +FT_DECLARE(ftdm_status_t) ftdm_channel_queue_dtmf(ftdm_channel_t *ftdmchan, const char *dtmf); +FT_DECLARE(void) ftdm_channel_flush_dtmf(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_time_t) ftdm_current_time_in_ms(void); +FT_DECLARE(ftdm_status_t) ftdm_span_poll_event(ftdm_span_t *span, uint32_t ms); +FT_DECLARE(ftdm_status_t) ftdm_span_next_event(ftdm_span_t *span, ftdm_event_t **event); +FT_DECLARE(ftdm_status_t) ftdm_span_find(uint32_t id, ftdm_span_t **span); +FT_DECLARE(ftdm_status_t) ftdm_span_create(ftdm_io_interface_t *zio, ftdm_span_t **span, const char *name); +FT_DECLARE(ftdm_status_t) ftdm_span_close_all(void); +FT_DECLARE(ftdm_status_t) ftdm_span_add_channel(ftdm_span_t *span, ftdm_socket_t sockfd, ftdm_chan_type_t type, ftdm_channel_t **chan); +FT_DECLARE(ftdm_status_t) ftdm_span_set_event_callback(ftdm_span_t *span, zio_event_cb_t event_callback); +FT_DECLARE(ftdm_status_t) ftdm_channel_add_to_group(const char* name, ftdm_channel_t* ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_group_add_channels(const char* name, ftdm_span_t* span, const char* val); +FT_DECLARE(ftdm_status_t) ftdm_channel_remove_from_group(ftdm_group_t* group, ftdm_channel_t* ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_group_find(uint32_t id, ftdm_group_t **group); +FT_DECLARE(ftdm_status_t) ftdm_group_find_by_name(const char *name, ftdm_group_t **group); +FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *name); +FT_DECLARE(ftdm_status_t) ftdm_channel_set_event_callback(ftdm_channel_t *ftdmchan, zio_event_cb_t event_callback); +FT_DECLARE(ftdm_status_t) ftdm_channel_open(uint32_t span_id, uint32_t chan_id, ftdm_channel_t **ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_span_channel_use_count(ftdm_span_t *span, uint32_t *count); +FT_DECLARE(ftdm_status_t) ftdm_group_channel_use_count(ftdm_group_t *group, uint32_t *count); +FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_span(uint32_t span_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_open_by_group(uint32_t group_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_close(ftdm_channel_t **ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_done(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_use(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_command(ftdm_channel_t *ftdmchan, ftdm_command_t command, void *obj); +FT_DECLARE(ftdm_status_t) ftdm_channel_wait(ftdm_channel_t *ftdmchan, ftdm_wait_flag_t *flags, int32_t to); +FT_DECLARE(ftdm_status_t) ftdm_channel_read(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t *datalen); +FT_DECLARE(void) ftdm_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor); +FT_DECLARE(ftdm_status_t) ftdm_channel_write(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t datasize, ftdm_size_t *datalen); +FT_DECLARE(ftdm_status_t) ftdm_channel_add_var(ftdm_channel_t *ftdmchan, const char *var_name, const char *value); +FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name); +FT_DECLARE(ftdm_status_t) ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_global_init(void); +FT_DECLARE(ftdm_status_t) ftdm_global_configuration(void); +FT_DECLARE(ftdm_status_t) ftdm_global_destroy(void); +FT_DECLARE(ftdm_status_t) ftdm_global_set_memory_handler(ftdm_memory_handler_t *handler); +FT_DECLARE(void) ftdm_global_set_crash_policy(ftdm_crash_policy_t policy); +FT_DECLARE(void) ftdm_global_set_logger(ftdm_logger_t logger); +FT_DECLARE(void) ftdm_global_set_default_logger(int level); +FT_DECLARE(uint32_t) ftdm_separate_string(char *buf, char delim, char **array, int arraylen); +FT_DECLARE(void) print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss); +FT_DECLARE(void) print_hex_bytes(uint8_t *data, ftdm_size_t dlen, char *buf, ftdm_size_t blen); +FT_DECLARE_NONSTD(int) ftdm_hash_equalkeys(void *k1, void *k2); +FT_DECLARE_NONSTD(uint32_t) ftdm_hash_hashfromstring(void *ky); +FT_DECLARE(uint32_t) ftdm_running(void); +FT_DECLARE(ftdm_status_t) ftdm_channel_complete_state(ftdm_channel_t *ftdmchan); +FT_DECLARE(ftdm_status_t) ftdm_channel_init(ftdm_channel_t *ftdmchan); +FT_DECLARE(int) ftdm_load_modules(void); +FT_DECLARE(ftdm_status_t) ftdm_unload_modules(void); +FT_DECLARE(ftdm_status_t) ftdm_configure_span(const char *type, ftdm_span_t *span, zio_signal_cb_t sig_cb, ...); +FT_DECLARE(ftdm_status_t) ftdm_configure_span_signaling(const char *type, ftdm_span_t *span, zio_signal_cb_t sig_cb, ftdm_conf_parameter_t *parameters); +FT_DECLARE(ftdm_status_t) ftdm_span_start(ftdm_span_t *span); +FT_DECLARE(ftdm_status_t) ftdm_span_stop(ftdm_span_t *span); +FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len); +FT_DECLARE(ftdm_status_t) ftdm_global_add_io_interface(ftdm_io_interface_t *io_interface); +FT_DECLARE(int) ftdm_load_module(const char *name); +FT_DECLARE(int) ftdm_load_module_assume(const char *name); +FT_DECLARE(ftdm_status_t) ftdm_span_find_by_name(const char *name, ftdm_span_t **span); +FT_DECLARE(char *) ftdm_api_execute(const char *type, const char *cmd); +FT_DECLARE(int) ftdm_vasprintf(char **ret, const char *fmt, va_list ap); + +ZIO_CODEC_FUNCTION(zio_slin2ulaw); +ZIO_CODEC_FUNCTION(zio_ulaw2slin); +ZIO_CODEC_FUNCTION(zio_slin2alaw); +ZIO_CODEC_FUNCTION(zio_alaw2slin); +ZIO_CODEC_FUNCTION(zio_ulaw2alaw); +ZIO_CODEC_FUNCTION(zio_alaw2ulaw); + +#ifdef DEBUG_LOCKS +#define ftdm_mutex_lock(_x) printf("++++++lock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_lock(_x) +#define ftdm_mutex_trylock(_x) printf("++++++try %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_trylock(_x) +#define ftdm_mutex_unlock(_x) printf("------unlock %s:%d\n", __FILE__, __LINE__) && _ftdm_mutex_unlock(_x) +#else +#define ftdm_mutex_lock(_x) _ftdm_mutex_lock(_x) +#define ftdm_mutex_trylock(_x) _ftdm_mutex_trylock(_x) +#define ftdm_mutex_unlock(_x) _ftdm_mutex_unlock(_x) +#endif + +/*! + \brief Assert condition +*/ +#define ftdm_assert(assertion, msg) \ + if (!(assertion)) { \ + ftdm_log(FTDM_LOG_CRIT, msg); \ + if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \ + ftdm_abort(); \ + } \ + } + +/*! + \brief Assert condition and return +*/ +#define ftdm_assert_return(assertion, retval, msg) \ + if (!(assertion)) { \ + ftdm_log(FTDM_LOG_CRIT, msg); \ + if (g_ftdm_crash_policy & FTDM_CRASH_ON_ASSERT) { \ + ftdm_abort(); \ + } else { \ + return retval; \ + } \ + } + +/*! + \brief Allocate uninitialized memory + \command chunksize the chunk size +*/ +#define ftdm_malloc(chunksize) g_ftdm_mem_handler.malloc(g_ftdm_mem_handler.pool, chunksize) + +/*! + \brief Allocate initialized memory + \command chunksize the chunk size +*/ +#define ftdm_calloc(elements, chunksize) g_ftdm_mem_handler.calloc(g_ftdm_mem_handler.pool, elements, chunksize) + +/*! + \brief Free chunk of memory + \command chunksize the chunk size +*/ +#define ftdm_free(chunk) g_ftdm_mem_handler.free(g_ftdm_mem_handler.pool, chunk) + +/*! + \brief Free a pointer and set it to NULL unless it already is NULL + \command it the pointer +*/ +#define ftdm_safe_free(it) if (it) { ftdm_free(it); it = NULL; } + +/*! + \brief Socket the given socket + \command it the socket +*/ +#define ftdm_socket_close(it) if (it > -1) { close(it); it = -1;} + +static __inline__ void ftdm_abort(void) +{ +#ifdef __cplusplus + ::abort(); +#else + abort(); +#endif +} + +static __inline__ void ftdm_set_state_all(ftdm_span_t *span, ftdm_channel_state_t state) +{ + uint32_t j; + ftdm_mutex_lock(span->mutex); + for(j = 1; j <= span->chan_count; j++) { + ftdm_set_state_locked((span->channels[j]), state); + } + ftdm_mutex_unlock(span->mutex); +} + +static __inline__ int ftdm_check_state_all(ftdm_span_t *span, ftdm_channel_state_t state) +{ + uint32_t j; + for(j = 1; j <= span->chan_count; j++) { + if (span->channels[j]->state != state || ftdm_test_flag(span->channels[j], FTDM_CHANNEL_STATE_CHANGE)) { + return 0; + } + } + + return 1; +} + +static __inline__ void ftdm_set_flag_all(ftdm_span_t *span, uint32_t flag) +{ + uint32_t j; + ftdm_mutex_lock(span->mutex); + for(j = 1; j <= span->chan_count; j++) { + ftdm_set_flag_locked((span->channels[j]), flag); + } + ftdm_mutex_unlock(span->mutex); +} + +static __inline__ void ftdm_clear_flag_all(ftdm_span_t *span, uint32_t flag) +{ + uint32_t j; + ftdm_mutex_lock(span->mutex); + for(j = 1; j <= span->chan_count; j++) { + ftdm_clear_flag_locked((span->channels[j]), flag); + } + ftdm_mutex_unlock(span->mutex); +} + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif + +/* 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: + */