# 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
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 $@
--- /dev/null
+/*
+ * 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 ------------------------------------------------------------*/
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
#include <assert.h>
#include "hashtable.h"
#include "zap_config.h"
+#include "g711.h"
+#include "libteletone.h"
#ifdef NDEBUG
#undef assert
typedef enum {
ZAP_SUCCESS,
- ZAP_FAIL
+ ZAP_FAIL,
+ ZAP_MEMERR
} zap_status_t;
typedef enum {
#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;
};
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);
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;
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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:
+ */
#include "openzap.h"
+#include <stdarg.h>
#ifdef ZAP_WANPIPE_SUPPORT
#include "zap_wanpipe.h"
#endif
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)
{
-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
--- /dev/null
+/*
+ * 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:
+ */
-CFLAGS +=-DZAP_ZT_SUPPORT
+MOD_CFLAGS +=-DZAP_ZT_SUPPORT
OBJS += zap_zt.o