add some weapons to arsenal
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@13 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
parent
699c263d04
commit
26a46f5dd0
|
@ -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 $@
|
||||
|
||||
|
|
|
@ -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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 <stdint.h>
|
||||
#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 ------------------------------------------------------------*/
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* libteletone
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <anthmct@yahoo.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* 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 <libteletone_generate.h>
|
||||
#include <libteletone_detect.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#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:
|
||||
*/
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* libteletone
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <steveu@coppice.org>
|
||||
* 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 <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* 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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 <libteletone.h>
|
||||
|
||||
/*! \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:
|
||||
*/
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* libteletone
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <anthmct@yahoo.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <libteletone.h>
|
||||
|
||||
|
||||
|
||||
/*! \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:
|
||||
*/
|
|
@ -62,6 +62,8 @@
|
|||
#include <assert.h>
|
||||
#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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* libteletone
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <steveu@coppice.org>
|
||||
* 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 <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* 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 <steveu@coppice.org>
|
||||
*
|
||||
* 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 <math.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <libteletone_detect.h>
|
||||
|
||||
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:
|
||||
*/
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* libteletone
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* 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 <anthmct@yahoo.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
*
|
||||
* 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 <libteletone.h>
|
||||
#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:
|
||||
*/
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
|
||||
#include "openzap.h"
|
||||
#include <stdarg.h>
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
*/
|
|
@ -1,2 +1,2 @@
|
|||
CFLAGS +=-DZAP_ZT_SUPPORT
|
||||
MOD_CFLAGS +=-DZAP_ZT_SUPPORT
|
||||
OBJS += zap_zt.o
|
||||
|
|
Loading…
Reference in New Issue