diff --git a/libs/freetdm/src/Makefile b/libs/freetdm/src/Makefile index ac6a8ffdec..2f7055b09c 100644 --- a/libs/freetdm/src/Makefile +++ b/libs/freetdm/src/Makefile @@ -29,7 +29,8 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -OBJS=hashtable.o hashtable_itr.o openzap.o zap_config.o + +OBJS=hashtable.o hashtable_itr.o openzap.o zap_config.o libteletone_detect.o libteletone_generate.o zap_buffer.o CFLAGS=$(ZAP_CFLAGS) -Iinclude MYLIB=libopenzap.a @@ -41,6 +42,9 @@ $(MYLIB): $(OBJS) ar rcs $(MYLIB) $(OBJS) ranlib $(MYLIB) +openzap.o: openzap.c + $(CC) $(MOD_CFLAGS) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@ + zap_wanpipe.o: zap_wanpipe.c $(CC) $(CFLAGS) $(ZAP_CFLAGS) $(WP_CFLAGS) -c $< -o $@ diff --git a/libs/freetdm/src/include/g711.h b/libs/freetdm/src/include/g711.h new file mode 100644 index 0000000000..8d1f6bf43a --- /dev/null +++ b/libs/freetdm/src/include/g711.h @@ -0,0 +1,384 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * g711.h - In line A-law and u-law conversion routines + * + * Written by Steve Underwood + * + * Copyright (C) 2001 Steve Underwood + * + * Despite my general liking of the GPL, I place this code in the + * public domain for the benefit of all mankind - even the slimy + * ones who might try to proprietize my work and use it to my + * detriment. + * + * $Id: g711.h,v 1.1 2006/06/07 15:46:39 steveu Exp $ + */ + +/*! \file */ + +/*! \page g711_page A-law and mu-law handling +Lookup tables for A-law and u-law look attractive, until you consider the impact +on the CPU cache. If it causes a substantial area of your processor cache to get +hit too often, cache sloshing will severely slow things down. The main reason +these routines are slow in C, is the lack of direct access to the CPU's "find +the first 1" instruction. A little in-line assembler fixes that, and the +conversion routines can be faster than lookup tables, in most real world usage. +A "find the first 1" instruction is available on most modern CPUs, and is a +much underused feature. + +If an assembly language method of bit searching is not available, these routines +revert to a method that can be a little slow, so the cache thrashing might not +seem so bad :( + +Feel free to submit patches to add fast "find the first 1" support for your own +favourite processor. + +Look up tables are used for transcoding between A-law and u-law, since it is +difficult to achieve the precise transcoding procedure laid down in the G.711 +specification by other means. +*/ + +#if !defined(_G711_H_) +#define _G711_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#ifndef __inline__ +#define __inline__ __inline +#endif +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef unsigned __int16 uint16_t; +#else +#include +#endif + +#if defined(__i386__) +/*! \brief Find the bit position of the highest set bit in a word + \param bits The word to be searched + \return The bit number of the highest set bit, or -1 if the word is zero. */ +static __inline__ int top_bit(unsigned int bits) +{ + int res; + + __asm__ __volatile__(" movl $-1,%%edx;\n" + " bsrl %%eax,%%edx;\n" + : "=d" (res) + : "a" (bits)); + return res; +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Find the bit position of the lowest set bit in a word + \param bits The word to be searched + \return The bit number of the lowest set bit, or -1 if the word is zero. */ +static __inline__ int bottom_bit(unsigned int bits) +{ + int res; + + __asm__ __volatile__(" movl $-1,%%edx;\n" + " bsfl %%eax,%%edx;\n" + : "=d" (res) + : "a" (bits)); + return res; +} +/*- End of function --------------------------------------------------------*/ +#elif defined(__x86_64__) +static __inline__ int top_bit(unsigned int bits) +{ + int res; + + __asm__ __volatile__(" movq $-1,%%rdx;\n" + " bsrq %%rax,%%rdx;\n" + : "=d" (res) + : "a" (bits)); + return res; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int bottom_bit(unsigned int bits) +{ + int res; + + __asm__ __volatile__(" movq $-1,%%rdx;\n" + " bsfq %%rax,%%rdx;\n" + : "=d" (res) + : "a" (bits)); + return res; +} +/*- End of function --------------------------------------------------------*/ +#else +static __inline__ int top_bit(unsigned int bits) +{ + int i; + + if (bits == 0) + return -1; + i = 0; + if (bits & 0xFFFF0000) + { + bits &= 0xFFFF0000; + i += 16; + } + if (bits & 0xFF00FF00) + { + bits &= 0xFF00FF00; + i += 8; + } + if (bits & 0xF0F0F0F0) + { + bits &= 0xF0F0F0F0; + i += 4; + } + if (bits & 0xCCCCCCCC) + { + bits &= 0xCCCCCCCC; + i += 2; + } + if (bits & 0xAAAAAAAA) + { + bits &= 0xAAAAAAAA; + i += 1; + } + return i; +} +/*- End of function --------------------------------------------------------*/ + +static __inline__ int bottom_bit(unsigned int bits) +{ + int i; + + if (bits == 0) + return -1; + i = 32; + if (bits & 0x0000FFFF) + { + bits &= 0x0000FFFF; + i -= 16; + } + if (bits & 0x00FF00FF) + { + bits &= 0x00FF00FF; + i -= 8; + } + if (bits & 0x0F0F0F0F) + { + bits &= 0x0F0F0F0F; + i -= 4; + } + if (bits & 0x33333333) + { + bits &= 0x33333333; + i -= 2; + } + if (bits & 0x55555555) + { + bits &= 0x55555555; + i -= 1; + } + return i; +} +/*- End of function --------------------------------------------------------*/ +#endif + +/* N.B. It is tempting to use look-up tables for A-law and u-law conversion. + * However, you should consider the cache footprint. + * + * A 64K byte table for linear to x-law and a 512 byte table for x-law to + * linear sound like peanuts these days, and shouldn't an array lookup be + * real fast? No! When the cache sloshes as badly as this one will, a tight + * calculation may be better. The messiest part is normally finding the + * segment, but a little inline assembly can fix that on an i386, x86_64 and + * many other modern processors. + */ + +/* + * Mu-law is basically as follows: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +/*#define ULAW_ZEROTRAP*/ /* turn on the trap as per the MIL-STD */ +#define ULAW_BIAS 0x84 /* Bias for linear code. */ + +/*! \brief Encode a linear sample to u-law + \param linear The sample to encode. + \return The u-law value. +*/ +static __inline__ uint8_t linear_to_ulaw(int linear) +{ + uint8_t u_val; + int mask; + int seg; + + /* Get the sign and the magnitude of the value. */ + if (linear < 0) + { + linear = ULAW_BIAS - linear; + mask = 0x7F; + } + else + { + linear = ULAW_BIAS + linear; + mask = 0xFF; + } + + seg = top_bit(linear | 0xFF) - 7; + + /* + * Combine the sign, segment, quantization bits, + * and complement the code word. + */ + if (seg >= 8) + u_val = (uint8_t) (0x7F ^ mask); + else + u_val = (uint8_t) (((seg << 4) | ((linear >> (seg + 3)) & 0xF)) ^ mask); +#ifdef ULAW_ZEROTRAP + /* Optional ITU trap */ + if (u_val == 0) + u_val = 0x02; +#endif + return u_val; +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Decode an u-law sample to a linear value. + \param ulaw The u-law sample to decode. + \return The linear value. +*/ +static __inline__ int16_t ulaw_to_linear(uint8_t ulaw) +{ + int t; + + /* Complement to obtain normal u-law value. */ + ulaw = ~ulaw; + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = (((ulaw & 0x0F) << 3) + ULAW_BIAS) << (((int) ulaw & 0x70) >> 4); + return (int16_t) ((ulaw & 0x80) ? (ULAW_BIAS - t) : (t - ULAW_BIAS)); +} +/*- End of function --------------------------------------------------------*/ + +/* + * A-law is basically as follows: + * + * Linear Input Code Compressed Code + * ----------------- --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ + +#define ALAW_AMI_MASK 0x55 + +/*! \brief Encode a linear sample to A-law + \param linear The sample to encode. + \return The A-law value. +*/ +static __inline__ uint8_t linear_to_alaw(int linear) +{ + int mask; + int seg; + + if (linear >= 0) + { + /* Sign (bit 7) bit = 1 */ + mask = ALAW_AMI_MASK | 0x80; + } + else + { + /* Sign (bit 7) bit = 0 */ + mask = ALAW_AMI_MASK; + linear = -linear - 8; + } + + /* Convert the scaled magnitude to segment number. */ + seg = top_bit(linear | 0xFF) - 7; + if (seg >= 8) + { + if (linear >= 0) + { + /* Out of range. Return maximum value. */ + return (uint8_t) (0x7F ^ mask); + } + /* We must be just a tiny step below zero */ + return (uint8_t) (0x00 ^ mask); + } + /* Combine the sign, segment, and quantization bits. */ + return (uint8_t) (((seg << 4) | ((linear >> ((seg) ? (seg + 3) : 4)) & 0x0F)) ^ mask); +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Decode an A-law sample to a linear value. + \param alaw The A-law sample to decode. + \return The linear value. +*/ +static __inline__ int16_t alaw_to_linear(uint8_t alaw) +{ + int i; + int seg; + + alaw ^= ALAW_AMI_MASK; + i = ((alaw & 0x0F) << 4); + seg = (((int) alaw & 0x70) >> 4); + if (seg) + i = (i + 0x108) << (seg - 1); + else + i += 8; + return (int16_t) ((alaw & 0x80) ? i : -i); +} +/*- End of function --------------------------------------------------------*/ + +/*! \brief Transcode from A-law to u-law, using the procedure defined in G.711. + \param alaw The A-law sample to transcode. + \return The best matching u-law value. +*/ +uint8_t alaw_to_ulaw(uint8_t alaw); + +/*! \brief Transcode from u-law to A-law, using the procedure defined in G.711. + \param alaw The u-law sample to transcode. + \return The best matching A-law value. +*/ +uint8_t ulaw_to_alaw(uint8_t ulaw); + +#ifdef __cplusplus +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/libs/freetdm/src/include/libteletone.h b/libs/freetdm/src/include/libteletone.h new file mode 100644 index 0000000000..aaf7b0ed47 --- /dev/null +++ b/libs/freetdm/src/include/libteletone.h @@ -0,0 +1,126 @@ +/* + * libteletone + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 libteletone + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * libteletone.h -- Tone Generator/Detector + * + * + * + * Exception: + * The author hereby grants the use of this source code under the + * following license if and only if the source code is distributed + * as part of the openzap library. Any use or distribution of this + * source code outside the scope of the openzap library will nullify the + * following license and reinact the MPL 1.1 as stated above. + * + * 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. + */ +#ifndef LIBTELETONE_H +#define LIBTELETONE_H + +#ifdef __cplusplus +extern "C" { +#endif +#define TELETONE_MAX_DTMF_DIGITS 128 +#define TELETONE_MAX_TONES 6 +#define TELETONE_TONE_RANGE 127 + +typedef double teletone_process_t; + +/*! \file libteletone.h + \brief Top level include file + + This file should be included by applications using the library +*/ + +/*! \brief An abstraction to store a tone mapping */ +typedef struct { + /*! An array of tone frequencies */ + teletone_process_t freqs[TELETONE_MAX_TONES]; +} teletone_tone_map_t; + +#if !defined(M_PI) +/* C99 systems may not define M_PI */ +#define M_PI 3.14159265358979323846264338327 +#endif + +#ifdef _MSC_VER +typedef __int16 int16_t; +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef __cplusplus +} +#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 expandtab: + */ diff --git a/libs/freetdm/src/include/libteletone_detect.h b/libs/freetdm/src/include/libteletone_detect.h new file mode 100644 index 0000000000..eda4e49514 --- /dev/null +++ b/libs/freetdm/src/include/libteletone_detect.h @@ -0,0 +1,280 @@ +/* + * libteletone + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 tone_detect.c - General telephony tone detection, and specific detection of DTMF. + * + * + * The Initial Developer of the Original Code is + * Stephen Underwood + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * The the original interface designed by Steve Underwood was preserved to retain + *the optimizations when considering DTMF tones though the names were changed in the interest + * of namespace. + * + * Much less efficient expansion interface was added to allow for the detection of + * a single arbitrary tone combination which may also exceed 2 simultaneous tones. + * (controlled by compile time constant TELETONE_MAX_TONES) + * + * Copyright (C) 2006 Anthony Minessale II + * + * + * libteletone_detect.c Tone Detection Code + * + * + ********************************************************************************* + * + * Derived from tone_detect.h - General telephony tone detection, and specific + * detection of DTMF. + * + * Copyright (C) 2001 Steve Underwood + * + * Despite my general liking of the GPL, I place this code in the + * public domain for the benefit of all mankind - even the slimy + * ones who might try to proprietize my work and use it to my + * detriment. + * + * + * Exception: + * The author hereby grants the use of this source code under the + * following license if and only if the source code is distributed + * as part of the openzap library. Any use or distribution of this + * source code outside the scope of the openzap library will nullify the + * following license and reinact the MPL 1.1 as stated above. + * + * 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. + */ + +#ifndef LIBTELETONE_DETECT_H +#define LIBTELETONE_DETECT_H + +#ifdef __cplusplus +extern "C" { +#endif +#include + +/*! \file libteletone_detect.h + \brief Tone Detection Routines + + This module is responsible for tone detection specifics +*/ + +#ifndef FALSE +#define FALSE 0 +#ifndef TRUE +#define TRUE (!FALSE) +#endif +#endif + +/* Basic DTMF specs: + * + * Minimum tone on = 40ms + * Minimum tone off = 50ms + * Maximum digit rate = 10 per second + * Normal twist <= 8dB accepted + * Reverse twist <= 4dB accepted + * S/N >= 15dB will detect OK + * Attenuation <= 26dB will detect OK + * Frequency tolerance +- 1.5% will detect, +-3.5% will reject + */ + +#define DTMF_THRESHOLD 8.0e7 +#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ +#define DTMF_REVERSE_TWIST 2.5 /* 4dB */ +#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ +#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ +#define DTMF_2ND_HARMONIC_ROW 2.5 /* 4dB */ +#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ +#define GRID_FACTOR 4 +#define BLOCK_LEN 102 +#define M_TWO_PI 2.0*M_PI + +/*! \brief A continer for the elements of a Goertzel Algorithm (The names are from his formula) */ +typedef struct { + teletone_process_t v2; + teletone_process_t v3; + teletone_process_t fac; +} teletone_goertzel_state_t; + +/*! \brief A container for a DTMF detection state.*/ +typedef struct { + int hit1; + int hit2; + int hit3; + int hit4; + int mhit; + + teletone_goertzel_state_t row_out[GRID_FACTOR]; + teletone_goertzel_state_t col_out[GRID_FACTOR]; + teletone_goertzel_state_t row_out2nd[GRID_FACTOR]; + teletone_goertzel_state_t col_out2nd[GRID_FACTOR]; + teletone_process_t energy; + + int current_sample; + char digits[TELETONE_MAX_DTMF_DIGITS + 1]; + int current_digits; + int detected_digits; + int lost_digits; + int digit_hits[16]; +} teletone_dtmf_detect_state_t; + +/*! \brief An abstraction to store the coefficient of a tone frequency */ +typedef struct { + teletone_process_t fac; +} teletone_detection_descriptor_t; + +/*! \brief A container for a single multi-tone detection +TELETONE_MAX_TONES dictates the maximum simultaneous tones that can be present +in a multi-tone representation. +*/ +typedef struct { + int sample_rate; + + teletone_detection_descriptor_t tdd[TELETONE_MAX_TONES]; + teletone_goertzel_state_t gs[TELETONE_MAX_TONES]; + teletone_goertzel_state_t gs2[TELETONE_MAX_TONES]; + int tone_count; + + teletone_process_t energy; + int current_sample; + + int min_samples; + int total_samples; + + int positives; + int negatives; + int hits; + + int positive_factor; + int negative_factor; + int hit_factor; + +} teletone_multi_tone_t; + + +/*! + \brief Initilize a multi-frequency tone detector + \param mt the multi-frequency tone descriptor + \param map a representation of the multi-frequency tone +*/ +void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map); + +/*! + \brief Check a sample buffer for the presence of the mulit-frequency tone described by mt + \param mt the multi-frequency tone descriptor + \param sample_buffer an array aof 16 bit signed linear samples + \param samples the number of samples present in sample_buffer + \return true when the tone was detected or false when it is not +*/ +int teletone_multi_tone_detect (teletone_multi_tone_t *mt, + int16_t sample_buffer[], + int samples); + +/*! + \brief Initilize a DTMF detection state object + \param dtmf_detect_state the DTMF detection state to initilize + \param sample_rate the desired sample rate +*/ +void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate); + +/*! + \brief Check a sample buffer for the presence of DTMF digits + \param dtmf_detect_state the detection state object to check + \param sample_buffer an array aof 16 bit signed linear samples + \param samples the number of samples present in sample_buffer + \return true when DTMF was detected or false when it is not +*/ +int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state, + int16_t sample_buffer[], + int samples); +/*! + \brief retrieve any collected digits into a string buffer + \param dtmf_detect_state the detection state object to check + \param buf the string buffer to write to + \param max the maximum length of buf + \return the number of characters written to buf +*/ +int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, + char *buf, + int max); + +/*! + \brief Step through the Goertzel Algorithm for each sample in a buffer + \param goertzel_state the goertzel state to step the samples through + \param sample_buffer an array aof 16 bit signed linear samples + \param samples the number of samples present in sample_buffer +*/ +void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state, + int16_t sample_buffer[], + int samples); + +/*! + \brief Compute the result of the last applied step of the Goertzel Algorithm + \param goertzel_state the goertzel state to retrieve from + \return the computed value for consideration in furthur audio tests +*/ +teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state); + + + +#ifdef __cplusplus +} +#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 expandtab: + */ diff --git a/libs/freetdm/src/include/libteletone_generate.h b/libs/freetdm/src/include/libteletone_generate.h new file mode 100644 index 0000000000..3d625e8f52 --- /dev/null +++ b/libs/freetdm/src/include/libteletone_generate.h @@ -0,0 +1,215 @@ +/* + * libteletone + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 libteletone + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * libteletone.h -- Tone Generator + * + * + * + * Exception: + * The author hereby grants the use of this source code under the + * following license if and only if the source code is distributed + * as part of the openzap library. Any use or distribution of this + * source code outside the scope of the openzap library will nullify the + * following license and reinact the MPL 1.1 as stated above. + * + * 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. + */ +#ifndef LIBTELETONE_GENERATE_H +#define LIBTELETONE_GENERATE_H +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#include +#include +#include +#include + + + +/*! \file libteletone_generate.h + \brief Tone Generation Routines + + This module is responsible for tone generation specifics +*/ + +typedef int16_t teletone_audio_t; +struct teletone_generation_session; +typedef int (*tone_handler)(struct teletone_generation_session *ts, teletone_tone_map_t *map); + +/*! \brief An abstraction to store a tone generation session */ +struct teletone_generation_session { + /*! An array of tone mappings to character mappings */ + teletone_tone_map_t TONES[TELETONE_TONE_RANGE]; + /*! The number of channels the output audio should be in */ + int channels; + /*! The Rate in hz of the output audio */ + int rate; + /*! The duration (in samples) of the output audio */ + int duration; + /*! The duration of silence to append after the initial audio is generated */ + int wait; + /*! The duration (in samples) of the output audio (takes prescedence over actual duration value) */ + int tmp_duration; + /*! The duration of silence to append after the initial audio is generated (takes prescedence over actual wait value)*/ + int tmp_wait; + /*! Number of loops to repeat a single instruction*/ + int loops; + /*! Number of loops to repeat the entire set of instructions*/ + int LOOPS; + /*! Number to mutiply total samples by to determine when to begin ascent or decent e.g. 0=beginning 4=(last 25%) */ + int decay_factor; + /*! Direction to perform volume increase/decrease 1/-1*/ + int decay_direction; + /*! Number of samples between increase/decrease of volume */ + int decay_step; + /*! Volume factor of the tone */ + int volume; + /*! Debug on/off */ + int debug; + /*! FILE stream to write debug data to */ + FILE *debug_stream; + /*! Extra user data to attach to the session*/ + void *user_data; + /*! Buffer for storing sample data (dynamic) */ + teletone_audio_t *buffer; + /*! Size of the buffer */ + int datalen; + /*! In-Use size of the buffer */ + int samples; + /*! Callback function called during generation */ + int dynamic; + tone_handler handler; +}; + +typedef struct teletone_generation_session teletone_generation_session_t; + + +/*! + \brief Assign a set of tones to a tone_session indexed by a paticular index/character + \param ts the tone generation session + \param index the index to map the tone to + \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 + \return 0 +*/ +int teletone_set_tone(teletone_generation_session_t *ts, int index, ...); + +/*! + \brief Assign a set of tones to a single tone map + \param map the map to assign the tones to + \param ... up to TELETONE_MAX_TONES frequencies terminated by 0.0 + \return 0 +*/ +int teletone_set_map(teletone_tone_map_t *map, ...); + +/*! + \brief Initilize a tone generation session + \param ts the tone generation session to initilize + \param buflen the size of the buffer(in samples) to dynamically allocate + \param handler a callback function to execute when a tone generation instruction is complete + \param user_data optional user data to send + \return 0 +*/ +int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data); + +/*! + \brief Free the buffer allocated by a tone generation session + \param ts the tone generation session to destroy + \return 0 +*/ +int teletone_destroy_session(teletone_generation_session_t *ts); + +/*! + \brief Execute a single tone generation instruction + \param ts the tone generation session to consult for parameters + \param map the tone mapping to use for the frequencies + \return 0 +*/ +int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map); + +/*! + \brief Execute a tone generation script and call callbacks after each instruction + \param ts the tone generation session to execute on + \param cmd the script to execute + \return 0 +*/ +int teletone_run(teletone_generation_session_t *ts, char *cmd); + +#ifdef __cplusplus +} +#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 expandtab: + */ diff --git a/libs/freetdm/src/include/openzap.h b/libs/freetdm/src/include/openzap.h index 3424a4ca47..07d0f20f2f 100644 --- a/libs/freetdm/src/include/openzap.h +++ b/libs/freetdm/src/include/openzap.h @@ -62,6 +62,8 @@ #include #include "hashtable.h" #include "zap_config.h" +#include "g711.h" +#include "libteletone.h" #ifdef NDEBUG #undef assert @@ -115,7 +117,8 @@ struct zap_software_interface; typedef enum { ZAP_SUCCESS, - ZAP_FAIL + ZAP_FAIL, + ZAP_MEMERR } zap_status_t; typedef enum { @@ -205,6 +208,20 @@ typedef zap_status_t (*zint_write_t) ZINT_WRITE_ARGS ; #define ZINT_READ_MUZZLE assert(zchan != NULL); assert(data != NULL); assert(datalen != NULL) #define ZINT_WRITE_MUZZLE assert(zchan != NULL); assert(data != NULL); assert(datalen != NULL) +#define ZAP_PRE __FILE__, __FUNCTION__, __LINE__ +#define ZAP_LOG_DEBUG ZAP_PRE, 7 +#define ZAP_LOG_INFO ZAP_PRE, 6 +#define ZAP_LOG_NOTICE ZAP_PRE, 5 +#define ZAP_LOG_WARNING ZAP_PRE, 4 +#define ZAP_LOG_ERROR ZAP_PRE, 3 +#define ZAP_LOG_CRIT ZAP_PRE, 2 +#define ZAP_LOG_ALERT ZAP_PRE, 1 +#define ZAP_LOG_EMERG ZAP_PRE, 0 + +typedef void (*zap_logger_t)(char *file, const char *func, int line, int level, char *fmt, ...); +extern zap_logger_t global_logger; +#define zap_log global_logger; + struct zap_software_interface { const char *name; zint_configure_t configure; @@ -220,6 +237,7 @@ struct zap_software_interface { }; typedef struct zap_software_interface zap_software_interface_t; + zap_status_t zap_span_create(zap_software_interface_t *zint, zap_span_t **span); zap_status_t zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan); zap_status_t zap_span_destroy(zap_span_t **span); @@ -233,6 +251,8 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data zap_status_t zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t *datalen); zap_status_t zap_global_init(void); zap_status_t zap_global_destroy(void); +void zap_global_set_logger(zap_logger_t logger); +void zap_global_set_default_logger(void); typedef struct hashtable zap_hash_t; diff --git a/libs/freetdm/src/include/zap_buffer.h b/libs/freetdm/src/include/zap_buffer.h new file mode 100644 index 0000000000..cd16825787 --- /dev/null +++ b/libs/freetdm/src/include/zap_buffer.h @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#ifndef ZAP_BUFFER_H +#define ZAP_BUFFER_H + +#include "openzap.h" + +/** + * @defgroup zap_buffer Buffer Routines + * @ingroup buffer + * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers + * throughout the application. + * @{ + */ +struct zap_buffer; +typedef struct zap_buffer zap_buffer_t; + +/*! \brief Allocate a new dynamic zap_buffer + * \param buffer returned pointer to the new buffer + * \param blocksize length to realloc by as data is added + * \param start_len ammount of memory to reserve initially + * \param max_len length the buffer is allowed to grow to + * \return status + */ +zap_status_t zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len); + +/*! \brief Get the length of a zap_buffer_t + * \param buffer any buffer of type zap_buffer_t + * \return int size of the buffer. + */ +zap_size_t zap_buffer_len(zap_buffer_t *buffer); + +/*! \brief Get the freespace of a zap_buffer_t + * \param buffer any buffer of type zap_buffer_t + * \return int freespace in the buffer. + */ +zap_size_t zap_buffer_freespace(zap_buffer_t *buffer); + +/*! \brief Get the in use amount of a zap_buffer_t + * \param buffer any buffer of type zap_buffer_t + * \return int ammount of buffer curently in use + */ +zap_size_t zap_buffer_inuse(zap_buffer_t *buffer); + +/*! \brief Read data from a zap_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer. + * \param buffer any buffer of type zap_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + */ +zap_size_t zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen); + +/*! \brief Read data endlessly from a zap_buffer_t + * \param buffer any buffer of type zap_buffer_t + * \param data pointer to the read data to be returned + * \param datalen amount of data to be returned + * \return int ammount of data actually read + * \note Once you have read all the data from the buffer it will loop around. + */ +zap_size_t zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen); + +/*! \brief Assign a number of loops to read + * \param buffer any buffer of type zap_buffer_t + * \param loops the number of loops (-1 for infinite) + */ +void zap_buffer_set_loops(zap_buffer_t *buffer, int32_t loops); + +/*! \brief Write data into a zap_buffer_t up to the length of datalen + * \param buffer any buffer of type zap_buffer_t + * \param data pointer to the data to be written + * \param datalen amount of data to be written + * \return int amount of buffer used after the write, or 0 if no space available + */ +zap_size_t zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen); + +/*! \brief Remove data from the buffer + * \param buffer any buffer of type zap_buffer_t + * \param datalen amount of data to be removed + * \return int size of buffer, or 0 if unable to toss that much data + */ +zap_size_t zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen); + +/*! \brief Remove all data from the buffer + * \param buffer any buffer of type zap_buffer_t + */ +void zap_buffer_zero(zap_buffer_t *buffer); + +/*! \brief Destroy the buffer + * \param buffer buffer to destroy + * \note only neccessary on dynamic buffers (noop on pooled ones) + */ +void zap_buffer_destroy(zap_buffer_t **buffer); + +/** @} */ + + +#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 expandtab: + */ diff --git a/libs/freetdm/src/libteletone_detect.c b/libs/freetdm/src/libteletone_detect.c new file mode 100644 index 0000000000..8df7d569a4 --- /dev/null +++ b/libs/freetdm/src/libteletone_detect.c @@ -0,0 +1,453 @@ +/* + * libteletone + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 tone_detect.c - General telephony tone detection, and specific detection of DTMF. + * + * + * The Initial Developer of the Original Code is + * Stephen Underwood + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * The the original interface designed by Steve Underwood was preserved to retain + *the optimizations when considering DTMF tones though the names were changed in the interest + * of namespace. + * + * Much less efficient expansion interface was added to allow for the detection of + * a single arbitrary tone combination which may also exceed 2 simultaneous tones. + * (controlled by compile time constant TELETONE_MAX_TONES) + * + * Copyright (C) 2006 Anthony Minessale II + * + * + * libteletone_detect.c Tone Detection Code + * + * + ********************************************************************************* + * + * Derived from tone_detect.c - General telephony tone detection, and specific + * detection of DTMF. + * + * Copyright (C) 2001 Steve Underwood + * + * Despite my general liking of the GPL, I place this code in the + * public domain for the benefit of all mankind - even the slimy + * ones who might try to proprietize my work and use it to my + * detriment. + * + * + * Exception: + * The author hereby grants the use of this source code under the + * following license if and only if the source code is distributed + * as part of the openzap library. Any use or distribution of this + * source code outside the scope of the openzap library will nullify the + * following license and reinact the MPL 1.1 as stated above. + * + * 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. + */ + +#include +#ifndef _MSC_VER +#include +#endif +#include +#include +#include +#include +#include + +static teletone_detection_descriptor_t dtmf_detect_row[GRID_FACTOR]; +static teletone_detection_descriptor_t dtmf_detect_col[GRID_FACTOR]; +static teletone_detection_descriptor_t dtmf_detect_row_2nd[GRID_FACTOR]; +static teletone_detection_descriptor_t dtmf_detect_col_2nd[GRID_FACTOR]; + +static teletone_process_t dtmf_row[] = {697.0, 770.0, 852.0, 941.0}; +static teletone_process_t dtmf_col[] = {1209.0, 1336.0, 1477.0, 1633.0}; + + +static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; + +static void goertzel_init(teletone_goertzel_state_t *goertzel_state, teletone_detection_descriptor_t *tdesc) { + goertzel_state->v2 = goertzel_state->v3 = 0.0; + goertzel_state->fac = tdesc->fac; +} + +void teletone_goertzel_update(teletone_goertzel_state_t *goertzel_state, + int16_t sample_buffer[], + int samples) +{ + int i; + teletone_process_t v1; + + for (i = 0; i < samples; i++) { + v1 = goertzel_state->v2; + goertzel_state->v2 = goertzel_state->v3; + goertzel_state->v3 = goertzel_state->fac*goertzel_state->v2 - v1 + sample_buffer[i]; + } +} + +teletone_process_t teletone_goertzel_result (teletone_goertzel_state_t *goertzel_state) +{ + return goertzel_state->v3 * goertzel_state->v3 + goertzel_state->v2 * goertzel_state->v2 - goertzel_state->v2 * goertzel_state->v3 * goertzel_state->fac; +} + +void teletone_dtmf_detect_init (teletone_dtmf_detect_state_t *dtmf_detect_state, int sample_rate) +{ + int i; + teletone_process_t theta; + + dtmf_detect_state->hit1 = dtmf_detect_state->hit2 = 0; + + for (i = 0; i < GRID_FACTOR; i++) { + theta = M_TWO_PI*(dtmf_row[i]/(teletone_process_t)sample_rate); + dtmf_detect_row[i].fac = 2.0*cos(theta); + + theta = M_TWO_PI*(dtmf_col[i]/(teletone_process_t)sample_rate); + dtmf_detect_col[i].fac = 2.0*cos(theta); + + theta = M_TWO_PI*(dtmf_row[i]*2.0/(teletone_process_t)sample_rate); + dtmf_detect_row_2nd[i].fac = 2.0*cos(theta); + + theta = M_TWO_PI*(dtmf_col[i]*2.0/(teletone_process_t)sample_rate); + dtmf_detect_col_2nd[i].fac = 2.0*cos(theta); + + goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); + + dtmf_detect_state->energy = 0.0; + } + dtmf_detect_state->current_sample = 0; + dtmf_detect_state->detected_digits = 0; + dtmf_detect_state->lost_digits = 0; + dtmf_detect_state->digits[0] = '\0'; + dtmf_detect_state->mhit = 0; +} + +void teletone_multi_tone_init(teletone_multi_tone_t *mt, teletone_tone_map_t *map) +{ + teletone_process_t theta = 0; + int x = 0; + + if(!mt->min_samples) { + mt->min_samples = 102; + } + + if (!mt->positive_factor) { + mt->positive_factor = 2; + } + + if(!mt->negative_factor) { + mt->negative_factor = 10; + } + + if (!mt->hit_factor) { + mt->hit_factor = 2; + } + + if (!mt->sample_rate) { + mt->sample_rate = 8000; + } + + for(x = 0; x < TELETONE_MAX_TONES; x++) { + if ((int) map->freqs[x] == 0) { + break; + } + mt->tone_count++; + theta = M_TWO_PI*(map->freqs[x]/(teletone_process_t)mt->sample_rate); + mt->tdd[x].fac = 2.0 * cos(theta); + goertzel_init (&mt->gs[x], &mt->tdd[x]); + goertzel_init (&mt->gs2[x], &mt->tdd[x]); + } + +} + +int teletone_multi_tone_detect (teletone_multi_tone_t *mt, + int16_t sample_buffer[], + int samples) +{ + int sample, limit, j, x = 0; + teletone_process_t v1, famp; + teletone_process_t eng_sum = 0, eng_all[TELETONE_MAX_TONES]; + int gtest = 0, see_hit = 0; + + for (sample = 0; sample < samples; sample = limit) { + mt->total_samples++; + + if ((samples - sample) >= (mt->min_samples - mt->current_sample)) { + limit = sample + (mt->min_samples - mt->current_sample); + } else { + limit = samples; + } + + for (j = sample; j < limit; j++) { + famp = sample_buffer[j]; + + mt->energy += famp*famp; + + for(x = 0; x < mt->tone_count; x++) { + v1 = mt->gs[x].v2; + mt->gs[x].v2 = mt->gs[x].v3; + mt->gs[x].v3 = mt->gs[x].fac * mt->gs[x].v2 - v1 + famp; + + v1 = mt->gs2[x].v2; + mt->gs2[x].v2 = mt->gs2[x].v3; + mt->gs2[x].v3 = mt->gs2[x].fac*mt->gs2[x].v2 - v1 + famp; + } + } + + mt->current_sample += (limit - sample); + if (mt->current_sample < mt->min_samples) { + continue; + } + + eng_sum = 0; + for(x = 0; x < mt->tone_count; x++) { + eng_all[x] = teletone_goertzel_result (&mt->gs[x]); + eng_sum += eng_all[x]; + } + + gtest = 0; + for(x = 0; x < mt->tone_count; x++) { + gtest += teletone_goertzel_result (&mt->gs2[x]) < eng_all[x] ? 1 : 0; + } + + if ((gtest >= 2 || gtest == mt->tone_count) && eng_sum > 42.0 * mt->energy) { + if(mt->negatives) { + mt->negatives--; + } + mt->positives++; + + if(mt->positives >= mt->positive_factor) { + mt->hits++; + } + if (mt->hits >= mt->hit_factor) { + see_hit++; + mt->positives = mt->negatives = mt->hits = 0; + } + } else { + mt->negatives++; + if(mt->positives) { + mt->positives--; + } + if(mt->negatives > mt->negative_factor) { + mt->positives = mt->hits = 0; + } + } + + /* Reinitialise the detector for the next block */ + for(x = 0; x < mt->tone_count; x++) { + goertzel_init (&mt->gs[x], &mt->tdd[x]); + goertzel_init (&mt->gs2[x], &mt->tdd[x]); + } + + mt->energy = 0.0; + mt->current_sample = 0; + } + + return see_hit; +} + + +int teletone_dtmf_detect (teletone_dtmf_detect_state_t *dtmf_detect_state, + int16_t sample_buffer[], + int samples) +{ + teletone_process_t row_energy[GRID_FACTOR]; + teletone_process_t col_energy[GRID_FACTOR]; + teletone_process_t famp; + teletone_process_t v1; + int i; + int j; + int sample; + int best_row; + int best_col; + char hit; + int limit; + + hit = 0; + for (sample = 0; sample < samples; sample = limit) { + /* BLOCK_LEN is optimised to meet the DTMF specs. */ + if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) { + limit = sample + (BLOCK_LEN - dtmf_detect_state->current_sample); + } else { + limit = samples; + } + + for (j = sample; j < limit; j++) { + int x = 0; + famp = sample_buffer[j]; + + dtmf_detect_state->energy += famp*famp; + + for(x = 0; x < GRID_FACTOR; x++) { + v1 = dtmf_detect_state->row_out[x].v2; + dtmf_detect_state->row_out[x].v2 = dtmf_detect_state->row_out[x].v3; + dtmf_detect_state->row_out[x].v3 = dtmf_detect_state->row_out[x].fac*dtmf_detect_state->row_out[x].v2 - v1 + famp; + + v1 = dtmf_detect_state->col_out[x].v2; + dtmf_detect_state->col_out[x].v2 = dtmf_detect_state->col_out[x].v3; + dtmf_detect_state->col_out[x].v3 = dtmf_detect_state->col_out[x].fac*dtmf_detect_state->col_out[x].v2 - v1 + famp; + + v1 = dtmf_detect_state->col_out2nd[x].v2; + dtmf_detect_state->col_out2nd[x].v2 = dtmf_detect_state->col_out2nd[x].v3; + dtmf_detect_state->col_out2nd[x].v3 = dtmf_detect_state->col_out2nd[x].fac*dtmf_detect_state->col_out2nd[x].v2 - v1 + famp; + + v1 = dtmf_detect_state->row_out2nd[x].v2; + dtmf_detect_state->row_out2nd[x].v2 = dtmf_detect_state->row_out2nd[x].v3; + dtmf_detect_state->row_out2nd[x].v3 = dtmf_detect_state->row_out2nd[x].fac*dtmf_detect_state->row_out2nd[x].v2 - v1 + famp; + } + + } + + dtmf_detect_state->current_sample += (limit - sample); + if (dtmf_detect_state->current_sample < BLOCK_LEN) { + continue; + } + /* We are at the end of a DTMF detection block */ + /* Find the peak row and the peak column */ + row_energy[0] = teletone_goertzel_result (&dtmf_detect_state->row_out[0]); + col_energy[0] = teletone_goertzel_result (&dtmf_detect_state->col_out[0]); + + for (best_row = best_col = 0, i = 1; i < GRID_FACTOR; i++) { + row_energy[i] = teletone_goertzel_result (&dtmf_detect_state->row_out[i]); + if (row_energy[i] > row_energy[best_row]) { + best_row = i; + } + col_energy[i] = teletone_goertzel_result (&dtmf_detect_state->col_out[i]); + if (col_energy[i] > col_energy[best_col]) { + best_col = i; + } + } + hit = 0; + /* Basic signal level test and the twist test */ + if (row_energy[best_row] >= DTMF_THRESHOLD && + col_energy[best_col] >= DTMF_THRESHOLD && + col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST && + col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) { + /* Relative peak test */ + for (i = 0; i < GRID_FACTOR; i++) { + if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) || + (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) { + break; + } + } + /* ... and second harmonic test */ + if (i >= GRID_FACTOR && (row_energy[best_row] + col_energy[best_col]) > 42.0*dtmf_detect_state->energy && + teletone_goertzel_result (&dtmf_detect_state->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] && + teletone_goertzel_result (&dtmf_detect_state->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) { + hit = dtmf_positions[(best_row << 2) + best_col]; + /* Look for two successive similar results */ + /* The logic in the next test is: + We need two successive identical clean detects, with + something different preceeding it. This can work with + back to back differing digits. More importantly, it + can work with nasty phones that give a very wobbly start + to a digit. */ + if (hit == dtmf_detect_state->hit3 && dtmf_detect_state->hit3 != dtmf_detect_state->hit2) { + dtmf_detect_state->mhit = hit; + dtmf_detect_state->digit_hits[(best_row << 2) + best_col]++; + dtmf_detect_state->detected_digits++; + if (dtmf_detect_state->current_digits < TELETONE_MAX_DTMF_DIGITS) { + dtmf_detect_state->digits[dtmf_detect_state->current_digits++] = hit; + dtmf_detect_state->digits[dtmf_detect_state->current_digits] = '\0'; + } + else + { + dtmf_detect_state->lost_digits++; + } + } + } + } + dtmf_detect_state->hit1 = dtmf_detect_state->hit2; + dtmf_detect_state->hit2 = dtmf_detect_state->hit3; + dtmf_detect_state->hit3 = hit; + /* Reinitialise the detector for the next block */ + for (i = 0; i < GRID_FACTOR; i++) { + goertzel_init (&dtmf_detect_state->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&dtmf_detect_state->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&dtmf_detect_state->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&dtmf_detect_state->col_out2nd[i], &dtmf_detect_col_2nd[i]); + } + dtmf_detect_state->energy = 0.0; + dtmf_detect_state->current_sample = 0; + } + if ((!dtmf_detect_state->mhit) || (dtmf_detect_state->mhit != hit)) { + dtmf_detect_state->mhit = 0; + return(0); + } + return (hit); +} + + +int teletone_dtmf_get (teletone_dtmf_detect_state_t *dtmf_detect_state, + char *buf, + int max) +{ + if (max > dtmf_detect_state->current_digits) { + max = dtmf_detect_state->current_digits; + } + if (max > 0) { + memcpy (buf, dtmf_detect_state->digits, max); + memmove (dtmf_detect_state->digits, dtmf_detect_state->digits + max, dtmf_detect_state->current_digits - max); + dtmf_detect_state->current_digits -= max; + } + buf[max] = '\0'; + return max; +} + +/* 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 expandtab: + */ diff --git a/libs/freetdm/src/libteletone_generate.c b/libs/freetdm/src/libteletone_generate.c new file mode 100644 index 0000000000..4e388c8d3b --- /dev/null +++ b/libs/freetdm/src/libteletone_generate.c @@ -0,0 +1,467 @@ +/* + * libteletone + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 libteletone + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * libteletone.c -- Tone Generator + * + * + * + * Exception: + * The author hereby grants the use of this source code under the + * following license if and only if the source code is distributed + * as part of the openzap library. Any use or distribution of this + * source code outside the scope of the openzap library will nullify the + * following license and reinact the MPL 1.1 as stated above. + * + * 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. + */ + +#include +#define SMAX 32767 +#define SMIN -32768 +#define normalize_to_16bit(n) if (n > SMAX) n = SMAX; else if (n < SMIN) n = SMIN; + +#ifdef _MSC_VER +#pragma warning(disable:4706) +#endif + + +int teletone_set_tone(teletone_generation_session_t *ts, int index, ...) +{ + va_list ap; + int i = 0; + teletone_process_t x = 0; + + va_start(ap, index); + while (i <= TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) { + ts->TONES[index].freqs[i++] = x; + } + va_end(ap); + + return (i > TELETONE_MAX_TONES) ? -1 : 0; + +} + +int teletone_set_map(teletone_tone_map_t *map, ...) +{ + va_list ap; + int i = 0; + teletone_process_t x = 0; + + va_start(ap, map); + while (i <= TELETONE_MAX_TONES && (x = va_arg(ap, teletone_process_t))) { + map->freqs[i++] = x; + } + va_end(ap); + + return (i > TELETONE_MAX_TONES) ? -1 : 0; + +} + +int teletone_init_session(teletone_generation_session_t *ts, int buflen, tone_handler handler, void *user_data) +{ + memset(ts, 0, sizeof(*ts)); + ts->rate = 8000; + ts->channels = 1; + ts->duration = 2000; + ts->wait = 500; + ts->tmp_duration = -1; + ts->tmp_wait = -1; + ts->handler = handler; + ts->user_data = user_data; + ts->volume = 1500; + ts->decay_step = 0; + if (buflen) { + if ((ts->buffer = calloc(buflen, sizeof(teletone_audio_t))) == 0) { + return -1; + } + ts->datalen = buflen; + } else { + ts->dynamic = 1024; + } + /* Add Standard DTMF Tones */ + teletone_set_tone(ts, '1', 697.0, 1209.0, 0.0); + teletone_set_tone(ts, '2', 697.0, 1336.0, 0.0); + teletone_set_tone(ts, '3', 697.0, 1477.0, 0.0); + teletone_set_tone(ts, 'A', 697.0, 1633.0, 0.0); + teletone_set_tone(ts, '4', 770.0, 1209.0, 0.0); + teletone_set_tone(ts, '5', 770.0, 1336.0, 0.0); + teletone_set_tone(ts, '6', 770.0, 1477.0, 0.0); + teletone_set_tone(ts, 'B', 770.0, 1633.0, 0.0); + teletone_set_tone(ts, '7', 859.0, 1209.0, 0.0); + teletone_set_tone(ts, '8', 859.0, 1336.0, 0.0); + teletone_set_tone(ts, '9', 859.0, 1477.0, 0.0); + teletone_set_tone(ts, 'C', 859.0, 1633.0, 0.0); + teletone_set_tone(ts, '*', 941.0, 1209.0, 0.0); + teletone_set_tone(ts, '0', 941.0, 1336.0, 0.0); + teletone_set_tone(ts, '#', 941.0, 1477.0, 0.0); + teletone_set_tone(ts, 'D', 941.0, 1633.0, 0.0); + + return 0; +} + +int teletone_destroy_session(teletone_generation_session_t *ts) +{ + if (ts->buffer) { + free(ts->buffer); + ts->buffer = NULL; + ts->samples = 0; + } + return 0; +} + +static int ensure_buffer(teletone_generation_session_t *ts, int need) +{ + need += ts->samples; + need *= sizeof(teletone_audio_t); + need *= ts->channels; + + if (need > ts->datalen) { + ts->datalen = need + ts->dynamic; + if (!(ts->buffer = realloc(ts->buffer, ts->datalen))) { + return -1; + } + } + + return 0; +} + +int teletone_mux_tones(teletone_generation_session_t *ts, teletone_tone_map_t *map) +{ + teletone_process_t period = (1.0 / ts->rate) / ts->channels; + int i, c; + int freqlen = 0; + teletone_process_t tones[TELETONE_MAX_TONES]; + int decay = 0; + int duration; + int wait = 0; + teletone_process_t sample; + + ts->samples = 0; + + duration = (ts->tmp_duration > -1) ? ts->tmp_duration : ts->duration; + wait = (ts->tmp_wait > -1) ? ts->tmp_wait : ts->wait; + + if (map->freqs[0] > 0) { + if (ts->decay_step) { + if (ts->decay_factor) { + decay = (duration - (duration / ts->decay_factor)); + } else { + decay = 0; + } + } + if (ts->volume < 0) { + ts->volume = 0; + } + + for (freqlen = 0; map->freqs[freqlen] && freqlen < TELETONE_MAX_TONES; freqlen++) { + tones[freqlen] = (teletone_process_t) map->freqs[freqlen] * (2 * M_PI); + } + + if (ts->channels > 1) { + duration *= ts->channels; + } + + if (ts->dynamic) { + if (ensure_buffer(ts, duration)) { + return -1; + } + } + for (ts->samples = 0; ts->samples < ts->datalen && ts->samples < duration; ts->samples++) { + if (ts->decay_step && !(ts->samples % ts->decay_step) && ts->volume > 0 && ts->samples > decay) { + ts->volume += ts->decay_direction; + } + + sample = (teletone_process_t) 128; + + for (i = 0; i < freqlen; i++) { + sample += ((teletone_process_t) 2 * (ts->volume > 0 ? ts->volume : 1) * cos(tones[i] * ts->samples * period)); + } + normalize_to_16bit(sample); + ts->buffer[ts->samples] = (teletone_audio_t)sample; + + for (c = 1; c < ts->channels; c++) { + ts->buffer[ts->samples+1] = ts->buffer[ts->samples]; + ts->samples++; + } + + } + } + if (ts->dynamic) { + if (ensure_buffer(ts, wait)) { + return -1; + } + } + for (c = 0; c < ts->channels; c++) { + for (i = 0; i < wait && ts->samples < ts->datalen; i++) { + ts->buffer[ts->samples++] = 0; + } + } + + if (ts->debug && ts->debug_stream) { + if (map->freqs[0] <= 0) { + fprintf(ts->debug_stream, "wait %d (%dms)\n", wait, wait / (ts->rate / 1000)); + } else { + fprintf(ts->debug_stream, "Generate: ("); + + for (i = 0; i < TELETONE_MAX_TONES && map->freqs[i]; i++) { + fprintf(ts->debug_stream, "%s%0.2f", i == 0 ? "" : "+",map->freqs[i]); + } + + fprintf(ts->debug_stream, ") [volume %d; samples %d(%dms) x %d channel%s; wait %d(%dms); decay_factor %d; decay_step %d; wrote %d bytes]\n", + ts->volume, + duration, + duration / (ts->rate / 1000), + ts->channels, + ts->channels == 1 ? "" : "s", + wait, + wait / (ts->rate / 1000), + ts->decay_factor, + ts->decay_step, + ts->samples * 2); + } + } + return ts->samples; +} + +/* don't ask */ +static char *my_strdup (const char *s) +{ + size_t len = strlen (s) + 1; + void *new = malloc (len); + + if (new == NULL) { + return NULL; + } + + return (char *) memcpy (new, s, len); +} + +int teletone_run(teletone_generation_session_t *ts, char *cmd) +{ + char *data = NULL, *cur = NULL, *end = NULL; + int var = 0, LOOPING = 0; + + if (!cmd) { + return -1; + } + + do { + if (!(data = my_strdup(cmd))) { + return -1; + } + + cur = data; + + while (*cur) { + var = 0; + if (*cur == ' ' || *cur == '\r' || *cur == '\n') { + cur++; + continue; + } + + if ((end = strchr(cur, ';')) != 0) { + *end++ = '\0'; + } + + if (*(cur + 1) == '=') { + var = 1; + switch(*cur) { + case 'c': + ts->channels = atoi(cur + 2); + break; + case 'r': + ts->rate = atoi(cur + 2); + break; + case 'd': + ts->duration = atoi(cur + 2) * (ts->rate / 1000); + break; + case 'v': + ts->volume = atoi(cur + 2); + break; + case '>': + ts->decay_factor = atoi(cur + 2); + ts->decay_direction = -1; + break; + case '<': + ts->decay_factor = atoi(cur + 2); + ts->decay_direction = 1; + break; + case '+': + ts->decay_step = atoi(cur + 2); + break; + case 'w': + ts->wait = atoi(cur + 2) * (ts->rate / 1000); + break; + case 'l': + ts->loops = atoi(cur + 2); + break; + case 'L': + if (!LOOPING) { + ts->LOOPS = atoi(cur + 2); + } + LOOPING++; + break; + } + } else { + while (*cur) { + char *p = NULL, *e = NULL; + teletone_tone_map_t mymap, *mapp = NULL; + + if (*cur == ' ' || *cur == '\r' || *cur == '\n') { + cur++; + continue; + } + + ts->tmp_duration = -1; + ts->tmp_wait = -1; + + memset(&mymap, 0, sizeof(mymap)); + + if (*(cur + 1) == '(') { + p = cur + 2; + if (*cur) { + char *next; + int i = 0; + if ((e = strchr(p, ')')) != 0) { + *e++ = '\0'; + } + do { + if ((next = strchr(p, ',')) != 0) { + *next++ = '\0'; + } + if (i == 0) { + ts->tmp_duration = atoi(p) * (ts->rate / 1000); + i++; + } else if (i == 1) { + ts->tmp_wait = atoi(p) * (ts->rate / 1000); + i++; + } else { + mymap.freqs[i++ - 2] = atof(p); + } + p = next; + + } while (next && (i-2) < TELETONE_MAX_TONES); + if (i > 2 && *cur == '%') { + mapp = &mymap; + } else if ((i != 2 || *cur == '%')) { + if (ts->debug && ts->debug_stream) { + fprintf(ts->debug_stream, "Syntax Error!\n"); + } + goto bottom; + } + } + } + + if (*cur && !mapp) { + if (*cur > 0 && *cur < TELETONE_TONE_RANGE) { + mapp = &ts->TONES[(int)*cur]; + } else if (ts->debug && ts->debug_stream) { + fprintf(ts->debug_stream, "Map [%c] Out Of Range!\n", *cur); + } + } + + if (mapp) { + if (mapp->freqs[0]) { + if (ts->handler) { + do { + ts->handler(ts, mapp); + if (ts->loops > 0) { + ts->loops--; + } + } while (ts->loops); + } + } else if (ts->debug && ts->debug_stream) { + fprintf(ts->debug_stream, "Ignoring Empty Map [%c]!\n", *cur); + } + } + + if (e) { + cur = e; + } else { + cur++; + } + } + } + + if (end) { + cur = end; + } else if (*cur){ + cur++; + } + } + bottom: + free(data); + data = NULL; + if (ts->LOOPS > 0) { + ts->LOOPS--; + } + + } while (ts->LOOPS); + + return 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 expandtab: + */ diff --git a/libs/freetdm/src/openzap.c b/libs/freetdm/src/openzap.c index 40c3173975..acf21e14f2 100644 --- a/libs/freetdm/src/openzap.c +++ b/libs/freetdm/src/openzap.c @@ -33,6 +33,7 @@ #include "openzap.h" +#include #ifdef ZAP_WANPIPE_SUPPORT #include "zap_wanpipe.h" #endif @@ -44,6 +45,78 @@ static struct { zap_hash_t *interface_hash; } globals; +static char *LEVEL_NAMES[] = { + "EMERG", + "ALERT", + "CRIT", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL +}; + +static char *cut_path(char *in) +{ + char *p, *ret = in; + char delims[] = "/\\"; + char *i; + + for (i = delims; *i; i++) { + p = in; + while ((p = strchr(p, *i)) != 0) { + ret = ++p; + } + } + return ret; +} + +static void null_logger(char *file, const char *func, int line, int level, char *fmt, ...) +{ + if (0) { + null_logger(file, func, line, level, fmt); + } +} + +static void default_logger(char *file, const char *func, int line, int level, char *fmt, ...) +{ + char *fp; + char data[1024]; + + va_list ap; + + fp = cut_path(file); + + va_start(ap, fmt); + + vsnprintf(data, sizeof(data), fmt, ap); + + if (level < 0 || level > 7) { + level = 7; + } + + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + + va_end(ap); + +} + +zap_logger_t global_logger = null_logger; + +void zap_global_set_logger(zap_logger_t logger) +{ + if (logger) { + global_logger = logger; + } else { + global_logger = null_logger; + } +} + +void zap_global_set_default_logger(void) +{ + global_logger = default_logger; +} static int equalkeys(const void *k1, const void *k2) { diff --git a/libs/freetdm/src/wanpipe b/libs/freetdm/src/wanpipe index 4f410a083b..917220c04e 100644 --- a/libs/freetdm/src/wanpipe +++ b/libs/freetdm/src/wanpipe @@ -1,7 +1,6 @@ -CFLAGS +=-DZAP_WANPIPE_SUPPORT +MOD_CFLAGS +=-DZAP_WANPIPE_SUPPORT OBJS += zap_wanpipe.o WANPIPE_INCLUDE=/usr/include/wanpipe -#WANPIPE_INCLUDE=../../wanpipe-3.1.0.p18/patches/kdrivers/include WP_CFLAGS =-I$(WANPIPE_INCLUDE) -I/usr/local/include -I/usr/src/linux/include -I. -I/usr/include WP_CFLAGS +=-D__LINUX__ -D_REENTRANT -D_GNU_SOURCE -DAFT_A104 -DWANPIPE_TDM_API -D_GNUC_ -DWANPIPE_TDM_API diff --git a/libs/freetdm/src/zap_buffer.c b/libs/freetdm/src/zap_buffer.c new file mode 100644 index 0000000000..b3df9ba0ab --- /dev/null +++ b/libs/freetdm/src/zap_buffer.c @@ -0,0 +1,264 @@ +/* + * 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. + */ + +#include "openzap.h" +#include "zap_buffer.h" + +static unsigned buffer_id = 0; + +struct zap_buffer { + unsigned char *data; + unsigned char *head; + zap_size_t used; + zap_size_t actually_used; + zap_size_t datalen; + zap_size_t max_len; + zap_size_t blocksize; + unsigned id; + int loops; +}; + + +zap_status_t zap_buffer_create(zap_buffer_t **buffer, zap_size_t blocksize, zap_size_t start_len, zap_size_t max_len) +{ + zap_buffer_t *new_buffer; + + if ((new_buffer = malloc(sizeof(*new_buffer)))) { + memset(new_buffer, 0, sizeof(*new_buffer)); + + if (start_len) { + if (!(new_buffer->data = malloc(start_len))) { + free(new_buffer); + return ZAP_MEMERR; + } + memset(new_buffer->data, 0, start_len); + } + + new_buffer->max_len = max_len; + new_buffer->datalen = start_len; + new_buffer->id = buffer_id++; + new_buffer->blocksize = blocksize; + new_buffer->head = new_buffer->data; + + *buffer = new_buffer; + return ZAP_SUCCESS; + } + + return ZAP_MEMERR; +} + +zap_size_t zap_buffer_len(zap_buffer_t *buffer) +{ + + assert(buffer != NULL); + + return buffer->datalen; + +} + + +zap_size_t zap_buffer_freespace(zap_buffer_t *buffer) +{ + assert(buffer != NULL); + + + if (buffer->max_len) { + return (zap_size_t) (buffer->max_len - buffer->used); + } + return 1000000; + +} + +zap_size_t zap_buffer_inuse(zap_buffer_t *buffer) +{ + assert(buffer != NULL); + + return buffer->used; +} + +zap_size_t zap_buffer_toss(zap_buffer_t *buffer, zap_size_t datalen) +{ + zap_size_t reading = 0; + + assert(buffer != NULL); + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + buffer->used -= reading; + buffer->head += reading; + + return buffer->used; +} + +void zap_buffer_set_loops(zap_buffer_t *buffer, int loops) +{ + buffer->loops = loops; +} + +zap_size_t zap_buffer_read_loop(zap_buffer_t *buffer, void *data, zap_size_t datalen) +{ + zap_size_t len; + if ((len = zap_buffer_read(buffer, data, datalen)) == 0) { + if (buffer->loops == 0) { + return 0; + } + buffer->head = buffer->data; + buffer->used = buffer->actually_used; + len = zap_buffer_read(buffer, data, datalen); + buffer->loops--; + } + return len; +} + +zap_size_t zap_buffer_read(zap_buffer_t *buffer, void *data, zap_size_t datalen) +{ + zap_size_t reading = 0; + + assert(buffer != NULL); + assert(data != NULL); + + + if (buffer->used < 1) { + buffer->used = 0; + return 0; + } else if (buffer->used >= datalen) { + reading = datalen; + } else { + reading = buffer->used; + } + + memcpy(data, buffer->head, reading); + buffer->used -= reading; + buffer->head += reading; + + /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */ + return reading; +} + +zap_size_t zap_buffer_write(zap_buffer_t *buffer, const void *data, zap_size_t datalen) +{ + zap_size_t freespace, actual_freespace; + + assert(buffer != NULL); + assert(data != NULL); + assert(buffer->data != NULL); + + if (!datalen) { + return buffer->used; + } + + actual_freespace = buffer->datalen - buffer->actually_used; + + if (actual_freespace < datalen) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + buffer->actually_used = buffer->used; + } + + freespace = buffer->datalen - buffer->used; + + /* + if (buffer->data != buffer->head) { + memmove(buffer->data, buffer->head, buffer->used); + buffer->head = buffer->data; + } + */ + + if (freespace < datalen) { + zap_size_t new_size, new_block_size; + + new_size = buffer->datalen + datalen; + new_block_size = buffer->datalen + buffer->blocksize; + + if (new_block_size > new_size) { + new_size = new_block_size; + } + buffer->head = buffer->data; + if (!(buffer->data = realloc(buffer->data, new_size))) { + return 0; + } + buffer->head = buffer->data; + buffer->datalen = new_size; + } + + + freespace = buffer->datalen - buffer->used; + + if (freespace < datalen) { + return 0; + } else { + memcpy(buffer->head + buffer->used, data, datalen); + buffer->used += datalen; + buffer->actually_used += datalen; + } + /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */ + + return buffer->used; +} + +void zap_buffer_zero(zap_buffer_t *buffer) +{ + assert(buffer != NULL); + assert(buffer->data != NULL); + + buffer->used = 0; + buffer->head = buffer->data; +} + +void zap_buffer_destroy(zap_buffer_t **buffer) +{ + if (*buffer) { + free((*buffer)->data); + free(*buffer); + } + + *buffer = NULL; +} + +/* 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 expandtab: + */ diff --git a/libs/freetdm/src/zt b/libs/freetdm/src/zt index d23da58c15..9e0f14d57c 100644 --- a/libs/freetdm/src/zt +++ b/libs/freetdm/src/zt @@ -1,2 +1,2 @@ -CFLAGS +=-DZAP_ZT_SUPPORT +MOD_CFLAGS +=-DZAP_ZT_SUPPORT OBJS += zap_zt.o