THRESH) {
+ af++;
+ printf("Active Frame: %ld unstables: %d\n",af, unstables);
+
+ find_aks(Sn, ak, NW, P, &Eres);
+ roots = lpc_to_lsp(&ak[1], P , lsp, 5, LSP_DELTA1);
+ if (roots == P) {
+ if (lspd) {
+ fprintf(flsp,"%f ",lsp[0]);
+ for(i=1; i
+#include
+#include
+
+#define N 160
+#define P 10
+
+int main(int argc, char *argv[])
+{
+ FILE *fin,*fres; /* input and output files */
+ short buf[N]; /* buffer of 16 bit speech samples */
+ float Sn[P+N]; /* input speech samples */
+ float res[N]; /* residual after LPC filtering */
+ float E;
+ float ak[P+1]; /* LP coeffs */
+
+ int frames; /* frames processed so far */
+ int i; /* loop variables */
+
+ if (argc < 3) {
+ printf("usage: %s InputFile ResidualFile\n", argv[0]);
+ exit(0);
+ }
+
+ /* Open files */
+
+ if ((fin = fopen(argv[1],"rb")) == NULL) {
+ printf("Error opening input file: %s\n",argv[1]);
+ exit(0);
+ }
+
+ if ((fres = fopen(argv[2],"wb")) == NULL) {
+ printf("Error opening output residual file: %s\n",argv[2]);
+ exit(0);
+ }
+
+ /* Initialise */
+
+ frames = 0;
+ for(i=0; i
+#include
+#include
+#include
+#include
+#include
+
+#define N 160
+#define P 10
+
+#define LPC_FLOOR 0.0002 /* autocorrelation floor */
+#define LSP_DELTA1 0.2 /* grid spacing for LSP root searches */
+#define NDFT 256 /* DFT size for SD calculation */
+
+/* Speex lag window */
+
+const float lag_window[11] = {
+ 1.00000, 0.99716, 0.98869, 0.97474, 0.95554, 0.93140, 0.90273, 0.86998,
+ 0.83367, 0.79434, 0.75258
+};
+
+/*---------------------------------------------------------------------------*\
+
+ find_aks_for_lsp()
+
+ This function takes a frame of samples, and determines the linear
+ prediction coefficients for that frame of samples. Modified version of
+ find_aks from lpc.c to include autocorrelation noise floor and lag window
+ to match Speex processing steps prior to LSP conversion.
+
+\*---------------------------------------------------------------------------*/
+
+void find_aks_for_lsp(
+ float Sn[], /* Nsam samples with order sample memory */
+ float a[], /* order+1 LPCs with first coeff 1.0 */
+ int Nsam, /* number of input speech samples */
+ int order, /* order of the LPC analysis */
+ float *E /* residual energy */
+)
+{
+ float Wn[N]; /* windowed frame of Nsam speech samples */
+ float R[P+1]; /* order+1 autocorrelation values of Sn[] */
+ int i;
+
+ hanning_window(Sn,Wn,Nsam);
+
+ autocorrelate(Wn,R,Nsam,order);
+ R[0] += LPC_FLOOR;
+ assert(order == 10); /* lag window only defined for order == 10 */
+ for(i=0; i<=order; i++)
+ R[i] *= lag_window[i];
+ levinson_durbin(R,a,order);
+
+ *E = 0.0;
+ for(i=0; i<=order; i++)
+ *E += a[i]*R[i];
+ if (*E < 0.0)
+ *E = 1E-12;
+}
+
+/*---------------------------------------------------------------------------*\
+
+ MAIN
+
+\*---------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+ FILE *fin; /* input speech files */
+ short buf[N]; /* buffer of 16 bit speech samples */
+ float Sn[P+N]; /* input speech samples */
+ float E;
+ float ak[P+1]; /* LP coeffs */
+ float ak_[P+1]; /* quantised LP coeffs */
+ float lsp[P];
+ float lsp_[P]; /* quantised LSPs */
+ int roots; /* number of LSP roots found */
+ int frames; /* frames processed so far */
+ int i; /* loop variables */
+
+ SpeexBits bits;
+
+ float sd; /* SD for this frame */
+ float totsd; /* accumulated SD so far */
+ int gt2,gt4; /* number of frames > 2 and 4 dB SD */
+ int unstables; /* number of unstable LSP frames */
+
+ if (argc < 2) {
+ printf("usage: %s InputFile\n", argv[0]);
+ exit(0);
+ }
+
+ /* Open files */
+
+ if ((fin = fopen(argv[1],"rb")) == NULL) {
+ printf("Error opening input file: %s\n",argv[1]);
+ exit(0);
+ }
+
+ /* Initialise */
+
+ frames = 0;
+ for(i=0; i 2.0) gt2++;
+ if (sd > 4.0) gt4++;
+ totsd += sd;
+ }
+ else
+ unstables++;
+ }
+
+ fclose(fin);
+
+ printf("frames = %d Av sd = %3.2f dB", frames, totsd/frames);
+ printf(" >2 dB %3.2f%% >4 dB %3.2f%% unstables: %d\n",gt2*100.0/frames,
+ gt4*100.0/frames, unstables);
+
+ return 0;
+}
+
diff --git a/libs/libcodec2/unittest/sd.c b/libs/libcodec2/unittest/sd.c
new file mode 100644
index 0000000000..f77b5099d5
--- /dev/null
+++ b/libs/libcodec2/unittest/sd.c
@@ -0,0 +1,84 @@
+/*--------------------------------------------------------------------------*\
+
+ FILE........: sd.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 20/7/93
+
+ Function to determine spectral distortion between two sets of LPCs.
+
+\*--------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define MAX_N 2048 /* maximum DFT size */
+
+#include
+#include "four1.h"
+#include "comp.h"
+#include "sd.h"
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: spectral_dist()
+
+ AUTHOR......: David Rowe
+ DATE CREATED: 20/7/93
+
+ This function returns the soectral distoertion between two
+ sets of LPCs.
+
+\*---------------------------------------------------------------------------*/
+
+float spectral_dist(float ak1[], float ak2[], int p, int n)
+/* float ak1[]; unquantised set of p+1 LPCs */
+/* float ak2[]; quantised set of p+1 LPCs */
+/* int p; LP order */
+/* int n; DFT size to use for SD calculations (power of 2) */
+{
+ COMP A1[MAX_N]; /* DFT of ak1[] */
+ COMP A2[MAX_N]; /* DFT of ak2[] */
+ float P1,P2; /* power of current bin */
+ float sd;
+ int i;
+
+ for(i=0; i
+#include
+#include
+#include
+#include
+#include "defines.h"
+#include "codec2.h"
+#include "quantise.h"
+#include "interp.h"
+
+/* CODEC2 struct copies from codec2.c to help with testing */
+
+typedef struct {
+ float Sn[M]; /* input speech */
+ float w[M]; /* time domain hamming window */
+ COMP W[FFT_ENC]; /* DFT of w[] */
+ float Pn[2*N]; /* trapezoidal synthesis window */
+ float Sn_[2*N]; /* synthesised speech */
+ float prev_Wo; /* previous frame's pitch estimate */
+ float ex_phase; /* excitation model phase track */
+ float bg_est; /* background noise estimate for post filter */
+ MODEL prev_model; /* model parameters from 20ms ago */
+} CODEC2;
+
+void analyse_one_frame(CODEC2 *c2, MODEL *model, short speech[]);
+void synthesise_one_frame(CODEC2 *c2, short speech[], MODEL *model, float ak[]);
+
+int test1()
+{
+ FILE *fin, *fout;
+ short buf[N];
+ void *c2;
+ CODEC2 *c3;
+ MODEL model;
+ float ak[LPC_ORD+1];
+ float lsps[LPC_ORD];
+
+ c2 = codec2_create();
+ c3 = (CODEC2*)c2;
+
+ fin = fopen("../raw/hts1a.raw", "rb");
+ assert(fin != NULL);
+ fout = fopen("hts1a_test.raw", "wb");
+ assert(fout != NULL);
+
+ while(fread(buf, sizeof(short), N, fin) == N) {
+ analyse_one_frame(c3, &model, buf);
+ speech_to_uq_lsps(lsps, ak, c3->Sn, c3->w, LPC_ORD);
+ synthesise_one_frame(c3, buf, &model, ak);
+ fwrite(buf, sizeof(short), N, fout);
+ }
+
+ codec2_destroy(c2);
+
+ fclose(fin);
+ fclose(fout);
+
+ return 0;
+}
+
+int test2()
+{
+ FILE *fin, *fout;
+ short buf[2*N];
+ void *c2;
+ CODEC2 *c3;
+ MODEL model, model_interp;
+ float ak[LPC_ORD+1];
+ int voiced1, voiced2;
+ int lsp_indexes[LPC_ORD];
+ int lpc_correction;
+ int energy_index;
+ int Wo_index;
+ char bits[CODEC2_BITS_PER_FRAME];
+ int nbit;
+ int i;
+
+ c2 = codec2_create();
+ c3 = (CODEC2*)c2;
+
+ fin = fopen("../raw/hts1a.raw", "rb");
+ assert(fin != NULL);
+ fout = fopen("hts1a_test.raw", "wb");
+ assert(fout != NULL);
+
+ while(fread(buf, sizeof(short), 2*N, fin) == 2*N) {
+ /* first 10ms analysis frame - we just want voicing */
+
+ analyse_one_frame(c3, &model, buf);
+ voiced1 = model.voiced;
+
+ /* second 10ms analysis frame */
+
+ analyse_one_frame(c3, &model, &buf[N]);
+ voiced2 = model.voiced;
+
+ Wo_index = encode_Wo(model.Wo);
+ encode_amplitudes(lsp_indexes,
+ &lpc_correction,
+ &energy_index,
+ &model,
+ c3->Sn,
+ c3->w);
+ nbit = 0;
+ pack(bits, &nbit, Wo_index, WO_BITS);
+ for(i=0; iprev_model, &model);
+
+ synthesise_one_frame(c3, buf, &model_interp, ak);
+ synthesise_one_frame(c3, &buf[N], &model, ak);
+
+ memcpy(&c3->prev_model, &model, sizeof(MODEL));
+ fwrite(buf, sizeof(short), 2*N, fout);
+ }
+
+ codec2_destroy(c2);
+
+ fclose(fin);
+ fclose(fout);
+
+ return 0;
+}
+
+int test3()
+{
+ FILE *fin, *fout, *fbits;
+ short buf1[2*N];
+ short buf2[2*N];
+ char bits[CODEC2_BITS_PER_FRAME];
+ void *c2;
+
+ c2 = codec2_create();
+
+ fin = fopen("../raw/hts1a.raw", "rb");
+ assert(fin != NULL);
+ fout = fopen("hts1a_test.raw", "wb");
+ assert(fout != NULL);
+ fbits = fopen("hts1a_test3.bit", "wb");
+ assert(fout != NULL);
+
+ while(fread(buf1, sizeof(short), 2*N, fin) == 2*N) {
+ codec2_encode(c2, bits, buf1);
+ fwrite(bits, sizeof(char), CODEC2_BITS_PER_FRAME, fbits);
+ codec2_decode(c2, buf2, bits);
+ fwrite(buf2, sizeof(short), CODEC2_SAMPLES_PER_FRAME, fout);
+ }
+
+ codec2_destroy(c2);
+
+ fclose(fin);
+ fclose(fout);
+ fclose(fbits);
+
+ return 0;
+}
+
+int main() {
+ test3();
+ return 0;
+}
diff --git a/libs/libcodec2/unittest/tcontphase.c b/libs/libcodec2/unittest/tcontphase.c
new file mode 100644
index 0000000000..ee2f662a48
--- /dev/null
+++ b/libs/libcodec2/unittest/tcontphase.c
@@ -0,0 +1,187 @@
+/*---------------------------------------------------------------------------*\
+
+ FILE........: tcontphase.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 11/9/09
+
+ Test program for developing continuous phase track synthesis algorithm.
+ However while developing this it was discovered that synthesis_mixed()
+ worked just as well.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define N 80 /* frame size */
+#define F 160 /* frames to synthesis */
+#define P 10 /* LPC order */
+
+#include
+#include
+#include
+#include
+#include "sine.h"
+#include "dump.h"
+#include "synth.h"
+#include "phase.h"
+
+int frames;
+
+float ak[] = {
+ 1.000000,
+-1.455836,
+ 1.361841,
+-0.879267,
+ 0.915985,
+-1.002202,
+ 0.944103,
+-0.743094,
+ 1.053356,
+-0.817491,
+ 0.431222
+};
+
+
+/*---------------------------------------------------------------------------*\
+
+ switch_present()
+
+ Searches the command line arguments for a "switch". If the switch is
+ found, returns the command line argument where it ws found, else returns
+ NULL.
+
+\*---------------------------------------------------------------------------*/
+
+int switch_present(sw,argc,argv)
+ char sw[]; /* switch in string form */
+ int argc; /* number of command line arguments */
+ char *argv[]; /* array of command line arguments in string form */
+{
+ int i; /* loop variable */
+
+ for(i=1; i
+#include
+#include
+#include
+#include
+#include
+
+#include "defines.h"
+#include "sine.h"
+#include "interp.h"
+
+void make_amp(MODEL *model, float f0, float cdB, float mdBHz)
+{
+ int i;
+ float mdBrad = mdBHz*FS/TWO_PI;
+
+ model->Wo = f0*TWO_PI/FS;
+ model->L = PI/model->Wo;
+ for(i=0; i<=model->L; i++)
+ model->A[i] = pow(10.0,(cdB + (float)i*model->Wo*mdBrad)/20.0);
+ model->voiced = 1;
+}
+
+void write_amp(char file[], MODEL *model)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(file,"wt");
+ for(i=1; i<=model->L; i++)
+ fprintf(f, "%f\t%f\n", model->Wo*i, model->A[i]);
+ fclose(f);
+}
+
+char *get_next_float(char *s, float *num)
+{
+ char *p = s;
+ char tmp[MAX_STR];
+
+ while(*p && !isspace(*p))
+ p++;
+ memcpy(tmp, s, p-s);
+ tmp[p-s] = 0;
+ *num = atof(tmp);
+
+ return p+1;
+}
+
+char *get_next_int(char *s, int *num)
+{
+ char *p = s;
+ char tmp[MAX_STR];
+
+ while(*p && !isspace(*p))
+ p++;
+ memcpy(tmp, s, p-s);
+ tmp[p-s] = 0;
+ *num = atoi(tmp);
+
+ return p+1;
+}
+
+void load_amp(MODEL *model, char file[], int frame)
+{
+ FILE *f;
+ int i;
+ char s[1024];
+ char *ps;
+
+ f = fopen(file,"rt");
+
+ for(i=0; iWo);
+ ps = get_next_int(ps, &model->L);
+ for(i=1; i<=model->L; i++)
+ ps = get_next_float(ps, &model->A[i]);
+
+ fclose(f);
+}
+
+int main() {
+ MODEL prev, next, interp;
+
+ //make_amp(&prev, 50.0, 60.0, 6E-3);
+ //make_amp(&next, 50.0, 40.0, 6E-3);
+ load_amp(&prev, "../src/hts1a_model.txt", 32);
+ load_amp(&next, "../src/hts1a_model.txt", 34);
+
+ interp.voiced = 1;
+ interpolate(&interp, &prev, &next);
+
+ write_amp("tinterp_prev.txt", &prev);
+ write_amp("tinterp_interp.txt", &interp);
+ write_amp("tinterp_next.txt", &next);
+
+ return 0;
+}
diff --git a/libs/libcodec2/unittest/tnlp.c b/libs/libcodec2/unittest/tnlp.c
new file mode 100644
index 0000000000..4abf69c4ef
--- /dev/null
+++ b/libs/libcodec2/unittest/tnlp.c
@@ -0,0 +1,148 @@
+/*---------------------------------------------------------------------------*\
+
+ FILE........: tnlp.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 23/3/93
+
+ Test program for non linear pitch estimation functions.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define N 80 /* frame size */
+#define M 320 /* pitch analysis window size */
+#define PITCH_MIN 20
+#define PITCH_MAX 160
+#define TNLP
+
+#include
+#include
+#include
+#include
+
+#include "defines.h"
+#include "dump.h"
+#include "sine.h"
+#include "nlp.h"
+
+int frames;
+
+/*---------------------------------------------------------------------------*\
+
+ switch_present()
+
+ Searches the command line arguments for a "switch". If the switch is
+ found, returns the command line argument where it ws found, else returns
+ NULL.
+
+\*---------------------------------------------------------------------------*/
+
+int switch_present(sw,argc,argv)
+ char sw[]; /* switch in string form */
+ int argc; /* number of command line arguments */
+ char *argv[]; /* array of command line arguments in string form */
+{
+ int i; /* loop variable */
+
+ for(i=1; i
+#include
+#include
+#include
+#include
+
+#include "defines.h"
+#include "dump.h"
+#include "quantise.h"
+
+int test_Wo_quant();
+int test_lsp_quant();
+int test_lsp(int lsp_number, int levels, float max_error_hz);
+int test_energy_quant(int levels, float max_error_dB);
+
+int main() {
+ quantise_init();
+ test_Wo_quant();
+ test_lsp_quant();
+ test_energy_quant(E_LEVELS, 0.5*(E_MAX_DB - E_MIN_DB)/E_LEVELS);
+
+ return 0;
+}
+
+int test_lsp_quant() {
+ test_lsp( 1, 16, 12.5);
+ test_lsp( 2, 16, 12.5);
+ test_lsp( 3, 16, 25);
+ test_lsp( 4, 16, 50);
+ test_lsp( 5, 16, 50);
+ test_lsp( 6, 16, 50);
+ test_lsp( 7, 16, 50);
+ test_lsp( 8, 8, 50);
+ test_lsp( 9, 8, 50);
+ test_lsp(10, 4, 100);
+
+ return 0;
+}
+
+int test_energy_quant(int levels, float max_error_dB) {
+ FILE *fe;
+ float e,e_dec, error, low_e, high_e;
+ int index, index_in, index_out, i;
+
+ /* check 1:1 match between input and output levels */
+
+ for(i=0; i max_error_dB) {
+ printf("error: %f %f\n", error, max_error_dB);
+ exit(0);
+ }
+ }
+
+ fclose(fe);
+ return 0;
+}
+
+int test_lsp(int lsp_number, int levels, float max_error_hz) {
+ float lsp[LPC_ORD];
+ int indexes_in[LPC_ORD];
+ int indexes_out[LPC_ORD];
+ int indexes[LPC_ORD];
+ int i;
+ float lowf, highf, f, error;
+ char s[MAX_STR];
+ FILE *flsp;
+ float max_error_rads;
+
+ lsp_number--;
+ max_error_rads = max_error_hz*TWO_PI/FS;
+
+ for(i=0; i max_error_rads) {
+ printf("%d error: %f %f\n", lsp_number+1, error, max_error_rads);
+ exit(0);
+ }
+ }
+
+ fclose(flsp);
+
+ printf("OK\n");
+
+ return 0;
+}
+
+int test_Wo_quant() {
+ int c;
+ FILE *f;
+ float Wo,Wo_dec, error, step_size;
+ int index, index_in, index_out;
+
+ /* output Wo quant curve for plotting */
+
+ f = fopen("quant_pitch.txt","wt");
+
+ for(Wo=0.9*(TWO_PI/P_MAX); Wo<=1.1*(TWO_PI/P_MIN); Wo += 0.001) {
+ index = encode_Wo(Wo);
+ fprintf(f, "%f %d\n", Wo, index);
+ }
+
+ fclose(f);
+
+ /* check for all Wo codes we get 1:1 match between encoder
+ and decoder Wo levels */
+
+ for(c=0; c (step_size/2.0)) {
+ printf("error: %f step_size/2: %f\n", error, step_size/2.0);
+ exit(0);
+ }
+ fprintf(f,"%f\n",error);
+ }
+ printf("OK\n");
+
+ fclose(f);
+ return 0;
+}
diff --git a/libs/libcodec2/unittest/vqtrain.c b/libs/libcodec2/unittest/vqtrain.c
new file mode 100644
index 0000000000..b46d4fcf30
--- /dev/null
+++ b/libs/libcodec2/unittest/vqtrain.c
@@ -0,0 +1,297 @@
+/*--------------------------------------------------------------------------*\
+
+ FILE........: VQTRAIN.C
+ AUTHOR......: David Rowe
+ DATE CREATED: 23/2/95
+
+ This program trains vector quantisers using K dimensional Lloyd-Max
+ method.
+
+\*--------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*-----------------------------------------------------------------------*\
+
+ INCLUDES
+
+\*-----------------------------------------------------------------------*/
+
+#include
+#include
+#include
+#include
+#include
+
+/*-----------------------------------------------------------------------*\
+
+ DEFINES
+
+\*-----------------------------------------------------------------------*/
+
+#define DELTAQ 0.01 /* quiting distortion */
+#define MAX_STR 80 /* maximum string length */
+
+/*-----------------------------------------------------------------------*\
+
+ FUNCTION PROTOTYPES
+
+\*-----------------------------------------------------------------------*/
+
+void zero(float v[], int k);
+void acc(float v1[], float v2[], int k);
+void norm(float v[], int k, long n);
+long quantise(float cb[], float vec[], int k, int m, float *se);
+
+/*-----------------------------------------------------------------------*\
+
+ MAIN
+
+\*-----------------------------------------------------------------------*/
+
+int main(int argc, char *argv[]) {
+ long k,m; /* dimension and codebook size */
+ float *vec; /* current vector */
+ float *cb; /* vector codebook */
+ float *cent; /* centroids for each codebook entry */
+ long *n; /* number of vectors in this interval */
+ long J; /* number of vectors in training set */
+ long i,j;
+ long ind; /* index of current vector */
+ float se; /* squared error for this iteration */
+ float Dn,Dn_1; /* current and previous iterations distortion */
+ float delta; /* improvement in distortion */
+ FILE *ftrain; /* file containing training set */
+ FILE *fvq; /* file containing vector quantiser */
+
+ /* Interpret command line arguments */
+
+ if (argc != 5) {
+ printf("usage: vqtrain TrainFile K M VQFile\n");
+ exit(0);
+ }
+
+ /* Open training file */
+
+ ftrain = fopen(argv[1],"rb");
+ if (ftrain == NULL) {
+ printf("Error opening training database file: %s\n",argv[1]);
+ exit(1);
+ }
+
+ /* determine k and m, and allocate arrays */
+
+ k = atol(argv[2]);
+ m = atol(argv[3]);
+ printf("dimension K=%ld number of entries M=%ld\n", k,m);
+ vec = (float*)malloc(sizeof(float)*k);
+ cb = (float*)malloc(sizeof(float)*k*m);
+ cent = (float*)malloc(sizeof(float)*k*m);
+ n = (long*)malloc(sizeof(long)*m);
+ if (cb == NULL || cb == NULL || cent == NULL || vec == NULL) {
+ printf("Error in malloc.\n");
+ exit(1);
+ }
+
+ /* determine size of training set */
+
+ J = 0;
+ while(fread(vec, sizeof(float), k, ftrain) == k)
+ J++;
+ printf("J=%ld entries in training set\n", J);
+
+ /* set up initial codebook state from samples of training set */
+
+ rewind(ftrain);
+ fread(cb, sizeof(float), k*m, ftrain);
+
+ /* main loop */
+
+ Dn = 1E32;
+ j = 1;
+ do {
+ Dn_1 = Dn;
+
+ /* zero centroids */
+
+ for(i=0; i DELTAQ)
+ for(i=0; i DELTAQ);
+
+ /* save codebook to disk */
+
+ fvq = fopen(argv[4],"wt");
+ if (fvq == NULL) {
+ printf("Error opening VQ file: %s\n",argv[4]);
+ exit(1);
+ }
+
+ for(j=0; jsamples * 2);
}
}
- return ts->samples;
+ return ts->samples / ts->channels;
}
/* don't ask */
@@ -413,6 +413,9 @@ TELETONE_API(int) teletone_run(teletone_generation_session_t *ts, const char *cm
*e++ = '\0';
}
do {
+ if (!p) {
+ break;
+ }
if ((next = strchr(p, ',')) != 0) {
*next++ = '\0';
}
diff --git a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c
index 0eaf955196..ca42c2c578 100644
--- a/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c
+++ b/libs/openzap/src/ozmod/ozmod_zt/ozmod_zt.c
@@ -977,7 +977,7 @@ ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
*/
ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
{
- uint32_t i, event_id = 0;
+ uint32_t i, event_id = ZAP_OOB_INVALID;
zt_event_t zt_event_id = 0;
for(i = 1; i <= span->chan_count; i++) {
@@ -1025,6 +1025,8 @@ ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
event_id = ZAP_OOB_OFFHOOK;
} else if (span->channels[i]->type == ZAP_CHAN_TYPE_FXO) {
event_id = ZAP_OOB_RING_START;
+ } else {
+ event_id = ZAP_OOB_NOOP;
}
}
break;
diff --git a/libs/openzap/src/zap_io.c b/libs/openzap/src/zap_io.c
index 7d37a493c4..283a9fe332 100644
--- a/libs/openzap/src/zap_io.c
+++ b/libs/openzap/src/zap_io.c
@@ -1017,6 +1017,7 @@ OZ_DECLARE(zap_status_t) zap_channel_set_state(zap_channel_t *zchan, zap_channel
case ZAP_CHANNEL_STATE_RING:
case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
case ZAP_CHANNEL_STATE_PROGRESS:
+ case ZAP_CHANNEL_STATE_IDLE:
case ZAP_CHANNEL_STATE_GET_CALLERID:
case ZAP_CHANNEL_STATE_GENRING:
ok = 1;
diff --git a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
index d5bb617914..bd42743c9f 100644
--- a/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
+++ b/libs/sofia-sip/libsofia-sip-ua/http/sofia-sip/http.h
@@ -58,7 +58,11 @@ SOFIA_BEGIN_DECLS
#define HTTP_DEFAULT_SERV "80"
/** HTTP protocol identifier */
+#ifndef _MSC_VER
#define HTTP_PROTOCOL_TAG ((void *)0x48545450) /* 'HTTP' */
+#else
+#define HTTP_PROTOCOL_TAG ((void *)(UINT_PTR)0x48545450) /* 'HTTP' */
+#endif
/** HTTP parser flags */
enum {
diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c b/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
index 2be30b04b9..061cd5ef2a 100644
--- a/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
+++ b/libs/sofia-sip/libsofia-sip-ua/msg/msg_tag.c
@@ -50,7 +50,11 @@
#include
#include "sofia-sip/msg_tag_class.h"
+#ifndef _MSC_VER
#define NONE ((void*)-1)
+#else
+#define NONE ((void*)(INT_PTR)-1)
+#endif
int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size)
{
diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
index 91fd72316b..c633aa3632 100644
--- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
+++ b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_header.h
@@ -299,7 +299,12 @@ enum {
(h))
/** No header. */
+
+#ifndef _MSC_VER
#define MSG_HEADER_NONE ((msg_header_t *)-1)
+#else
+#define MSG_HEADER_NONE ((msg_header_t *)(INT_PTR)-1)
+#endif
SOFIA_END_DECLS
diff --git a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
index 4a9f234dec..033c551fdb 100644
--- a/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
+++ b/libs/sofia-sip/libsofia-sip-ua/msg/sofia-sip/msg_mime.h
@@ -235,7 +235,11 @@ msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n);
SOFIAPUBVAR char const msg_mime_version_1_0[];
/** MIME multipart parser table identifier. @HIDE */
+#ifndef _MSC_VER
#define MSG_MULTIPART_PROTOCOL_TAG ((void *)0x4d494d45) /* 'MIME' */
+#else
+#define MSG_MULTIPART_PROTOCOL_TAG ((void *)(UINT_PTR)0x4d494d45) /* 'MIME' */
+#endif
SOFIA_END_DECLS
diff --git a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c b/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
index 4287ae4359..a6c7d49ac6 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
+++ b/libs/sofia-sip/libsofia-sip-ua/nea/nea_server.c
@@ -41,7 +41,11 @@
#include "nea_debug.h"
+#ifndef _MSC_VER
#define NONE ((void *)- 1)
+#else
+#define NONE ((void *)(INT_PTR)- 1)
+#endif
#define SU_ROOT_MAGIC_T struct nea_server_s
#define SU_MSG_ARG_T tagi_t
diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
index 656aecc195..40ee1f8f85 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
+++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c
@@ -104,8 +104,11 @@ char const nta_version[] = PACKAGE_VERSION;
static char const __func__[] = "nta";
#endif
+#ifndef _MSC_VER
#define NONE ((void *)-1)
-
+#else
+#define NONE ((void *)(INT_PTR)-1)
+#endif
/* ------------------------------------------------------------------------- */
/** Resolving order */
diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
index bf35263d92..b96b1f31c0 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
+++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_dialog.c
@@ -53,7 +53,12 @@
#include
#ifndef NONE
+
+#ifndef _MSC_VER
#define NONE ((void *)-1)
+#else
+#define NONE ((void *)(INT_PTR)-1)
+#endif
#endif
/* ======================================================================== */
diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
index 318ccdd61d..97c88582a3 100644
--- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
+++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.h
@@ -83,7 +83,11 @@ typedef struct nua_ee_data {
nua_event_data_t ee_data[1];
} nua_ee_data_t;
+#ifndef _MSC_VER
#define NONE ((void *)-1)
+#else
+#define NONE ((void *)(INT_PTR)-1)
+#endif
typedef struct register_usage nua_registration_t;
diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
index 1a235ca4c8..37ae836598 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
+++ b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip.h
@@ -81,10 +81,18 @@ typedef enum {
#define SIP_METHOD_PUBLISH sip_method_publish, "PUBLISH"
/** Magic pointer value - never valid for SIP headers. @HI */
+#ifndef _MSC_VER
#define SIP_NONE ((void const *)-1L)
+#else
+#define SIP_NONE ((void const *)(INT_PTR)-1L)
+#endif
/** SIP protocol identifier @HIDE */
+#ifndef _MSC_VER
#define SIP_PROTOCOL_TAG ((void *)0x53495020) /* 'SIP'20 */
+#else
+#define SIP_PROTOCOL_TAG ((void *)(UINT_PTR)0x53495020) /* 'SIP'20 */
+#endif
enum {
/** Default port for SIP as integer */
diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
index de79e0f3a5..7f272a8e6f 100644
--- a/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
+++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa.c
@@ -56,7 +56,11 @@
#include
#include
+#ifndef _MSC_VER
#define NONE ((void *)-1)
+#else
+#define NONE ((void *)(INT_PTR)-1)
+#endif
#define XXX assert(!"implemented")
typedef unsigned longlong ull;
diff --git a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
index f94f9b2962..f104274ef4 100644
--- a/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
+++ b/libs/sofia-sip/libsofia-sip-ua/soa/soa_static.c
@@ -396,7 +396,11 @@ sdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from,
return NULL;
}
+#ifndef _MSC_VER
#define SDP_MEDIA_NONE ((sdp_media_t *)-1)
+#else
+#define SDP_MEDIA_NONE ((sdp_media_t *)(INT_PTR)-1)
+#endif
/** Find first matching media in table @a mm.
*
diff --git a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
index f660b2ce22..e494571f54 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
+++ b/libs/sofia-sip/libsofia-sip-ua/sresolv/sres.c
@@ -125,7 +125,7 @@ su_inline
ssize_t sres_recvfrom(sres_socket_t s, void *buffer, size_t length, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
- int retval, ilen;
+ int retval, ilen = 0;
if (fromlen)
ilen = *fromlen;
diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su.c b/libs/sofia-sip/libsofia-sip-ua/su/su.c
index 250b5d62d1..8067fdec60 100644
--- a/libs/sofia-sip/libsofia-sip-ua/su/su.c
+++ b/libs/sofia-sip/libsofia-sip-ua/su/su.c
@@ -434,7 +434,7 @@ ssize_t su_recv(su_socket_t s, void *buffer, size_t length, int flags)
ssize_t su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags,
su_sockaddr_t *from, socklen_t *fromlen)
{
- int retval, ilen;
+ int retval, ilen = 0;
if (fromlen)
ilen = *fromlen;
diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
index b56dd2d9bc..683b79a360 100644
--- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
+++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_internal.h
@@ -79,7 +79,11 @@
#endif
#ifndef NONE
+#ifndef _MSC_VER
#define NONE ((void *)-1)
+#else
+#define NONE ((void *)(INT_PTR)-1)
+#endif
#endif
SOFIA_BEGIN_DECLS
diff --git a/libs/spandsp/src/spandsp/private/t30.h b/libs/spandsp/src/spandsp/private/t30.h
index e56753e07d..b8a2e8be1c 100644
--- a/libs/spandsp/src/spandsp/private/t30.h
+++ b/libs/spandsp/src/spandsp/private/t30.h
@@ -60,10 +60,8 @@ struct t30_state_s
int supported_t30_features;
/*! \brief TRUE is ECM mode handling is enabled. */
int ecm_allowed;
-#if 0
/*! \brief TRUE if we are capable of retransmitting pages */
int retransmit_capable;
-#endif
/*! \brief The received DCS, formatted as an ASCII string, for inclusion
in the TIFF file. */
@@ -71,12 +69,12 @@ struct t30_state_s
/*! \brief The text which will be used in FAX page header. No text results
in no header line. */
char header_info[T30_MAX_PAGE_HEADER_INFO + 1];
-#if 0
/*! \brief TRUE for FAX page headers to overlay (i.e. replace) the beginning of the
page image. FALSE for FAX page headers to add to the overall length of
the page. */
int header_overlays_image;
-#endif
+ /*! \brief TRUE if remote T.30 procedural interrupts are allowed. */
+ int remote_interrupts_allowed;
/*! \brief The information fields received. */
t30_exchanged_info_t rx_info;
@@ -207,13 +205,6 @@ struct t30_state_s
/*! \brief This is only used in full duplex (e.g. ISDN) modes. */
int timer_t8;
- /* These fields are guessed based on compiler error forensics, I added them to fix the build -anthm */
- int remote_interrupts_allowed;
- int rtp_events;
- int rtn_events;
- int retransmit_capable;
- /* end guessed fields */
-
/*! \brief TRUE once the far end FAX entity has been detected. */
int far_end_detected;
@@ -283,12 +274,10 @@ struct t30_state_s
/*! \brief The current completion status. */
int current_status;
-#if 0
/*! \brief The number of RTP events */
int rtp_events;
/*! \brief The number of RTN events */
int rtn_events;
-#endif
/*! \brief the FCF2 field of the last PPS message we received. */
uint8_t last_pps_fcf2;
diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h
index 9df7321abd..a2fff2d28c 100644
--- a/libs/spandsp/src/spandsp/t30.h
+++ b/libs/spandsp/src/spandsp/t30.h
@@ -682,6 +682,10 @@ SPAN_DECLARE(void) t30_get_transfer_statistics(t30_state_t *s, t30_stats_t *t);
\param state TRUE to enable interrupt request, else FALSE. */
SPAN_DECLARE(void) t30_local_interrupt_request(t30_state_t *s, int state);
+/*! Allow remote interrupts of FAX exchange.
+ \brief Allow remote interrupts of FAX exchange.
+ \param s The T.30 context.
+ \param state TRUE to allow interruptd, else FALSE. */
SPAN_DECLARE(void) t30_remote_interrupts_allowed(t30_state_t *s, int state);
#if defined(__cplusplus)
diff --git a/libs/win32/openssl/libeay32.2010.vcxproj b/libs/win32/openssl/libeay32.2010.vcxproj
index 1157e5ca87..4d0d9a44ee 100644
--- a/libs/win32/openssl/libeay32.2010.vcxproj
+++ b/libs/win32/openssl/libeay32.2010.vcxproj
@@ -74,6 +74,10 @@
true
true
true
+ $(PlatformName)\libeay32\$(Configuration)\
+ $(PlatformName)\libeay32\$(Configuration)\
+ $(PlatformName)\libeay32\$(Configuration)\
+ $(PlatformName)\libeay32\$(Configuration)\
diff --git a/libs/win32/openssl/ssleay32.2010.vcxproj b/libs/win32/openssl/ssleay32.2010.vcxproj
index 8d6c22df18..1a444bb41f 100644
--- a/libs/win32/openssl/ssleay32.2010.vcxproj
+++ b/libs/win32/openssl/ssleay32.2010.vcxproj
@@ -73,6 +73,10 @@
true
true
true
+ $(PlatformName)\ssleay32\$(Configuration)\
+ $(PlatformName)\ssleay32\$(Configuration)\
+ $(PlatformName)\ssleay32\$(Configuration)\
+ $(PlatformName)\ssleay32\$(Configuration)\
diff --git a/scripts/perl/blacklist.pl b/scripts/perl/blacklist.pl
new file mode 100755
index 0000000000..f434669f36
--- /dev/null
+++ b/scripts/perl/blacklist.pl
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+#
+# Add this to acl.conf.xml
+#
+#
+#
+
+use Data::Dumper;
+use LWP::Simple;
+
+# http://www.infiltrated.net/voipabuse/addresses.txt
+# http://www.infiltrated.net/voipabuse/netblocks.txt
+
+
+my @addresses = split(/\n/, get("http://www.infiltrated.net/voipabuse/addresses.txt"));
+my @netblocks = split(/\n/, get("http://www.infiltrated.net/voipabuse/netblocks.txt"));
+
+print "\n";
+foreach $addr (@addresses) {
+ print " \n";
+}
+print "
\n";
+
+
+print "\n";
+foreach $netb (@netblocks) {
+ print " \n";
+}
+print "
\n";
diff --git a/scripts/perl/honeypot.pl b/scripts/perl/honeypot.pl
new file mode 100755
index 0000000000..ef52142cb1
--- /dev/null
+++ b/scripts/perl/honeypot.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+#
+# Add this to conf/dialplan/public but only if you wish to setup a honeypot.
+#
+#
+#
+
+use Data::Dumper;
+use LWP::Simple;
+
+# http://www.infiltrated.net/voipabuse/numberscalled.txt
+
+my @numberscalled = split(/\n/, get("http://www.infiltrated.net/voipabuse/numberscalled.txt"));
+
+foreach $number (@numberscalled) {
+ my ($num,$ts) = split(/\t/, $number);
+
+ print "\n";
+ print " \n";
+ print " \n";
+ print " \n";
+ print " \n";
+ print "\n";
+}
+
+
diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h
index 50dde95dc7..e77d5f74ef 100644
--- a/src/include/private/switch_core_pvt.h
+++ b/src/include/private/switch_core_pvt.h
@@ -233,6 +233,8 @@ struct switch_runtime {
switch_profile_timer_t *profile_timer;
double profile_time;
double min_idle_time;
+ int sql_buffer_len;
+ int max_sql_buffer_len;
};
extern struct switch_runtime runtime;
diff --git a/src/include/switch.h b/src/include/switch.h
index 7143c61d91..81684c59b0 100644
--- a/src/include/switch.h
+++ b/src/include/switch.h
@@ -91,7 +91,10 @@
#include
#pragma warning(pop)
#else
+/* work around for warnings in vs 2010 */
+#pragma warning (disable:6386)
#include
+#pragma warning (default:6386)
#endif
#else
#include
diff --git a/src/include/switch_config.h b/src/include/switch_config.h
index 2281a9bbc1..4115564f56 100644
--- a/src/include/switch_config.h
+++ b/src/include/switch_config.h
@@ -38,7 +38,7 @@
/**
* @defgroup config Config File Parser
* @ingroup core1
- * This module implements a basic interface and file format parser it may be depricated in favor of database entries
+ * This module implements a basic interface and file format parser it may be deprecated in favor of database entries
* or expanded to tie to external handlers in the future as necessary.
*
*
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 7275f26319..8b08db7d9d 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -1339,12 +1339,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_timer_destroy(switch_timer_t *timer)
\param pool the memory pool to use
\return SWITCH_STATUS_SUCCESS if the handle is allocated
*/
-SWITCH_DECLARE(switch_status_t) switch_core_codec_init(switch_codec_t *codec,
+#define switch_core_codec_init(_codec, _codec_name, _fmtp, _rate, _ms, _channels, _flags, _codec_settings, _pool) \
+ switch_core_codec_init_with_bitrate(_codec, _codec_name, _fmtp, _rate, _ms, _channels, 0, _flags, _codec_settings, _pool)
+SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec_t *codec,
const char *codec_name,
const char *fmtp,
uint32_t rate,
int ms,
int channels,
+ uint32_t bitrate,
uint32_t flags, const switch_codec_settings_t *codec_settings, switch_memory_pool_t *pool);
SWITCH_DECLARE(switch_status_t) switch_core_codec_copy(switch_codec_t *codec, switch_codec_t *new_codec, switch_memory_pool_t *pool);
diff --git a/src/include/switch_cpp.h b/src/include/switch_cpp.h
index ed14f108c7..0ede8e638f 100644
--- a/src/include/switch_cpp.h
+++ b/src/include/switch_cpp.h
@@ -292,7 +292,8 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
SWITCH_DECLARE(int) transfer(char *extension, char *dialplan = NULL, char *context = NULL);
- SWITCH_DECLARE(char *) read(int min_digits, int max_digits, const char *prompt_audio_file, int timeout, const char *valid_terminators);
+ SWITCH_DECLARE(char *) read(int min_digits, int max_digits,
+ const char *prompt_audio_file, int timeout, const char *valid_terminators, int digit_timeout = 0);
/** \brief Play a file into channel and collect dtmfs
*
@@ -306,7 +307,7 @@ SWITCH_DECLARE(void) consoleCleanLog(char *msg);
int max_digits,
int max_tries,
int timeout, char *terminators, char *audio_files, char *bad_input_audio_files,
- char *digits_regex, const char *var_name = NULL);
+ char *digits_regex, const char *var_name = NULL, int digit_timeout = 0);
/** \brief Play a file that resides on disk into the channel
*
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index 40ba1dc16f..4c562a51d7 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -369,7 +369,8 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
const char *audio_file,
const char *bad_input_audio_file,
const char *var_name, char *digit_buffer, uint32_t digit_buffer_length,
- const char *digits_regex);
+ const char *digits_regex,
+ uint32_t digit_timeout);
SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session_t *session,
switch_speech_handle_t *sh,
@@ -804,7 +805,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_read(switch_core_session_t *session,
uint32_t max_digits,
const char *prompt_audio_file,
const char *var_name,
- char *digit_buffer, switch_size_t digit_buffer_length, uint32_t timeout, const char *valid_terminators);
+ char *digit_buffer,
+ switch_size_t digit_buffer_length,
+ uint32_t timeout,
+ const char *valid_terminators,
+ uint32_t digit_timeout);
+
SWITCH_DECLARE(switch_status_t) switch_ivr_block_dtmf_session(switch_core_session_t *session);
SWITCH_DECLARE(switch_status_t) switch_ivr_unblock_dtmf_session(switch_core_session_t *session);
diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h
index 68719062b7..37c752bd3e 100644
--- a/src/include/switch_loadable_module.h
+++ b/src/include/switch_loadable_module.h
@@ -92,7 +92,7 @@ SWITCH_BEGIN_EXTERN_C
\brief Initilize the module backend and load all the modules
\return SWITCH_STATUS_SUCCESS when complete
*/
-SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(void);
+SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autoload);
/*!
\brief Shutdown the module backend and call the shutdown routine in all loaded modules
diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h
index 078b83d2fd..a6013a9386 100644
--- a/src/include/switch_module_interfaces.h
+++ b/src/include/switch_module_interfaces.h
@@ -570,42 +570,23 @@ struct switch_directory_handle {
void *private_info;
};
-
/* nobody has more setting than speex so we will let them set the standard */
/*! \brief Various codec settings (currently only relevant to speex) */
struct switch_codec_settings {
- /*! desired quality */
- int quality;
- /*! desired complexity */
- int complexity;
- /*! desired enhancement */
- int enhancement;
- /*! desired vad level */
- int vad;
- /*! desired vbr level */
- int vbr;
- /*! desired vbr quality */
- float vbr_quality;
- /*! desired abr level */
- int abr;
- /*! desired dtx setting */
- int dtx;
- /*! desired preprocessor settings */
- int preproc;
- /*! preprocessor vad settings */
- int pp_vad;
- /*! preprocessor gain control settings */
- int pp_agc;
- /*! preprocessor gain level */
- float pp_agc_level;
- /*! preprocessor denoise level */
- int pp_denoise;
- /*! preprocessor dereverb settings */
- int pp_dereverb;
- /*! preprocessor dereverb decay level */
- float pp_dereverb_decay;
- /*! preprocessor dereverb level */
- float pp_dereverb_level;
+ int unused;
+};
+
+/*! an abstract handle of a fmtp parsed by codec */
+struct switch_codec_fmtp {
+ /*! actual samples transferred per second for those who are not moron g722 RFC writers */
+ uint32_t actual_samples_per_second;
+ /*! bits transferred per second */
+ int bits_per_second;
+ /*! number of microseconds of media in one packet (ptime * 1000) */
+ int microseconds_per_packet;
+ /*! private data for the codec module to store handle specific info */
+ void *private_info;
+
};
/*! an abstract handle to a codec module */
@@ -618,8 +599,6 @@ struct switch_codec {
char *fmtp_in;
/*! fmtp line for local sdp */
char *fmtp_out;
- /*! codec settings for this handle */
- switch_codec_settings_t codec_settings;
/*! flags to modify behaviour */
uint32_t flags;
/*! the handle's memory pool */
@@ -678,6 +657,8 @@ struct switch_codec_interface {
const char *interface_name;
/*! a list of codec implementations related to the codec */
switch_codec_implementation_t *implementations;
+ /*! function to decode a codec fmtp parameters */
+ switch_core_codec_fmtp_parse_func_t parse_fmtp;
uint32_t codec_id;
switch_thread_rwlock_t *rwlock;
int refs;
diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h
index 7e6028a68b..7269a2b8d9 100644
--- a/src/include/switch_rtp.h
+++ b/src/include/switch_rtp.h
@@ -449,6 +449,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_stun_ping(switch_rtp_t *rtp_
SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, switch_rtp_bug_flag_t bugs);
SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_session, switch_memory_pool_t *pool);
+SWITCH_DECLARE(switch_byte_t) switch_rtp_check_auto_adj(switch_rtp_t *rtp_session);
/*!
\}
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 5a88cd5751..57c5661c7c 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -255,7 +255,8 @@ typedef enum {
SCF_USE_CLOCK_RT = (1 << 10),
SCF_VERBOSE_EVENTS = (1 << 11),
SCF_USE_WIN32_MONOTONIC = (1 << 12),
- SCF_AUTO_SCHEMAS = (1 << 13)
+ SCF_AUTO_SCHEMAS = (1 << 13),
+ SCF_MINIMAL = (1 << 14)
} switch_core_flag_enum_t;
typedef uint32_t switch_core_flag_t;
@@ -479,9 +480,16 @@ typedef struct {
switch_size_t flush_packet_count;
} switch_rtp_numbers_t;
+
+typedef struct {
+ uint32_t packet_count;
+ uint32_t octet_count;
+} switch_rtcp_numbers_t;
+
typedef struct {
switch_rtp_numbers_t inbound;
switch_rtp_numbers_t outbound;
+ switch_rtcp_numbers_t rtcp;
} switch_rtp_stats_t;
typedef enum {
@@ -762,9 +770,9 @@ typedef struct {
const char *T38FaxUdpEC;
const char *T38VendorInfo;
const char *remote_ip;
- uint32_t remote_port;
+ uint16_t remote_port;
const char *local_ip;
- uint32_t local_port;
+ uint16_t local_port;
} switch_t38_options_t;
/*!
@@ -1580,6 +1588,7 @@ typedef struct switch_core_thread_session switch_core_thread_session_t;
typedef struct switch_codec_implementation switch_codec_implementation_t;
typedef struct switch_buffer switch_buffer_t;
typedef struct switch_codec_settings switch_codec_settings_t;
+typedef struct switch_codec_fmtp switch_codec_fmtp_t;
typedef struct switch_odbc_handle switch_odbc_handle_t;
typedef struct switch_io_routines switch_io_routines_t;
@@ -1638,6 +1647,7 @@ typedef switch_status_t (*switch_core_codec_decode_func_t) (switch_codec_t *code
void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag);
typedef switch_status_t (*switch_core_codec_init_func_t) (switch_codec_t *, switch_codec_flag_t, const switch_codec_settings_t *codec_settings);
+typedef switch_status_t (*switch_core_codec_fmtp_parse_func_t) (const char *fmtp, switch_codec_fmtp_t *codec_fmtp);
typedef switch_status_t (*switch_core_codec_destroy_func_t) (switch_codec_t *);
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index f24cee5e9f..e5d70c43cc 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -139,6 +139,9 @@ static inline char *switch_strchr_strict(const char *in, char find, const char *
#define switch_is_valid_rate(_tmp) (_tmp == 8000 || _tmp == 12000 || _tmp == 16000 || _tmp == 24000 || _tmp == 32000 || _tmp == 11025 || _tmp == 22050 || _tmp == 44100 || _tmp == 48000)
+#ifdef _MSC_VER
+#pragma warning(disable:6011)
+#endif
static inline int switch_string_has_escaped_data(const char *in)
{
const char *i = strchr(in, '\\');
@@ -153,6 +156,9 @@ static inline int switch_string_has_escaped_data(const char *in)
return 0;
}
+#ifdef _MSC_VER
+#pragma warning(default:6011)
+#endif
SWITCH_DECLARE(switch_status_t) switch_b64_encode(unsigned char *in, switch_size_t ilen, unsigned char *out, switch_size_t olen);
SWITCH_DECLARE(switch_size_t) switch_b64_decode(char *in, char *out, switch_size_t olen);
@@ -171,6 +177,23 @@ static inline switch_bool_t switch_is_digit_string(const char *s)
return SWITCH_TRUE;
}
+
+static inline uint32_t switch_known_bitrate(switch_payload_t payload)
+{
+ switch(payload) {
+ case 0: /* PCMU */ return 64000;
+ case 3: /* GSM */ return 13200;
+ case 4: /* G723 */ return 6300;
+ case 7: /* LPC */ return 2400;
+ case 8: /* PCMA */ return 64000;
+ case 9: /* G722 */ return 64000;
+ case 18: /* G729 */ return 8000;
+ default: break;
+ }
+
+ return 0;
+}
+
SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size_t len);
@@ -353,7 +376,16 @@ switch_mutex_unlock(obj->flag_mutex);
#define switch_set_string(_dst, _src) switch_copy_string(_dst, _src, sizeof(_dst))
- static inline char *switch_sanitize_number(char *number)
+static inline uint32_t switch_default_ptime(const char *name, uint32_t number)
+{
+ if (!strcasecmp(name, "G723")) {
+ return 30;
+ }
+
+ return 20;
+}
+
+static inline char *switch_sanitize_number(char *number)
{
char *p = number, *q;
char warp[] = "/:";
@@ -455,6 +487,9 @@ static inline char *switch_safe_strdup(const char *it)
}
+#ifdef _MSC_VER
+#pragma warning(disable:6011)
+#endif
static inline char *switch_lc_strdup(const char *it)
{
char *dup;
@@ -487,6 +522,9 @@ static inline char *switch_uc_strdup(const char *it)
return NULL;
}
+#ifdef _MSC_VER
+#pragma warning(default:6011)
+#endif
/*!
@@ -680,7 +718,15 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo
SWITCH_DECLARE(int) switch_inet_pton(int af, const char *src, void *dst);
+SWITCH_DECLARE(const char *) switch_dow_int2str(int val);
+SWITCH_DECLARE(int) switch_dow_str2int(const char *exp);
+SWITCH_DECLARE(int) switch_dow_cmp(const char *exp, int val);
SWITCH_DECLARE(int) switch_number_cmp(const char *exp, int val);
+SWITCH_DECLARE(int) switch_tod_cmp(const char *exp, int val);
+
+SWITCH_DECLARE(int) switch_fulldate_cmp(const char *exp, switch_time_t *ts);
+SWITCH_DECLARE(void) switch_split_date(const char *exp, int *year, int *month, int *day);
+SWITCH_DECLARE(void) switch_split_time(const char *exp, int *hour, int *min, int *sec);
/*!
\brief Split a user@domain string as user and domain
diff --git a/src/include/switch_xml.h b/src/include/switch_xml.h
index 220e65df02..9b0fbb44f3 100644
--- a/src/include/switch_xml.h
+++ b/src/include/switch_xml.h
@@ -331,6 +331,7 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(_In_ uint8_t reload, _Out_ con
///\return SWITCH_STATUS_SUCCESS if successful
SWITCH_DECLARE(switch_status_t) switch_xml_init(_In_ switch_memory_pool_t *pool, _Out_ const char **err);
+SWITCH_DECLARE(switch_status_t) switch_xml_reload(const char **err);
SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void);
diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c
index e08757ba38..b58e647e3b 100644
--- a/src/mod/applications/mod_callcenter/mod_callcenter.c
+++ b/src/mod/applications/mod_callcenter/mod_callcenter.c
@@ -1259,7 +1259,7 @@ static switch_status_t load_config(void)
if (!strcasecmp(var, "debug")) {
globals.debug = atoi(val);
} else if (!strcasecmp(var, "odbc-dsn")) {
- globals.odbc_dsn = strdup(switch_xml_attr(param, "odbc-dsn"));
+ globals.odbc_dsn = strdup(val);
if (!zstr(globals.odbc_dsn)) {
if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
@@ -1498,7 +1498,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
/* Update Agents Items */
/* Do not remove uuid of the agent if we are a standby agent */
- sql = switch_mprintf("UPDATE agents SET %q last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
+ sql = switch_mprintf("UPDATE agents SET %s last_bridge_end = %ld, talk_time = talk_time + (%ld-last_bridge_start) WHERE name = '%q' AND system = '%q';"
, (strcasecmp(h->agent_type, CC_AGENT_TYPE_UUID_STANDBY)?"uuid = '',":""), (long) switch_epoch_time_now(NULL), (long) switch_epoch_time_now(NULL), h->agent_name, h->agent_system);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
@@ -2675,9 +2675,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
{
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
-
- /* connect my internal structure to the blank pointer passed to me */
- *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ switch_status_t status;
memset(&globals, 0, sizeof(globals));
globals.pool = pool;
@@ -2685,11 +2683,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
switch_core_hash_init(&globals.queue_hash, globals.pool);
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+ if ((status = load_config()) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+
switch_mutex_lock(globals.mutex);
globals.running = 1;
switch_mutex_unlock(globals.mutex);
- load_config();
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
if (!AGENT_DISPATCH_THREAD_STARTED) {
cc_agent_dispatch_thread_start();
diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c
index e1eb2a6b6a..1fb1c95c47 100644
--- a/src/mod/applications/mod_commands/mod_commands.c
+++ b/src/mod/applications/mod_commands/mod_commands.c
@@ -135,7 +135,7 @@ SWITCH_STANDARD_API(nat_map_function)
switch_bool_t sticky = SWITCH_FALSE;
if (!cmd) {
- goto error;
+ goto usage;
}
if (!switch_nat_is_initialized()) {
@@ -147,9 +147,8 @@ SWITCH_STANDARD_API(nat_map_function)
switch_assert(mydata);
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
-
if (argc < 1) {
- goto error;
+ goto usage;
}
if (argv[0] && switch_stristr("status", argv[0])) {
tmp = switch_nat_status();
@@ -197,6 +196,10 @@ SWITCH_STANDARD_API(nat_map_function)
error:
stream->write_function(stream, "false");
+ goto ok;
+
+ usage:
+ stream->write_function(stream, "USAGE: nat_map [status|reinit|republish] | [add|del] [tcp|udp] [sticky]");
ok:
@@ -605,11 +608,12 @@ SWITCH_STANDARD_API(in_group_function)
SWITCH_STANDARD_API(user_data_function)
{
- switch_xml_t x_domain, xml = NULL, x_user = NULL, x_param, x_params;
+ switch_xml_t x_domain, xml = NULL, x_user = NULL, x_group = NULL, x_param, x_params;
int argc;
char *mydata = NULL, *argv[3], *key = NULL, *type = NULL, *user, *domain;
char delim = ' ';
const char *container = "params", *elem = "param";
+ const char *result = NULL;
switch_event_t *params = NULL;
if (zstr(cmd) || !(mydata = strdup(cmd))) {
@@ -637,10 +641,10 @@ SWITCH_STANDARD_API(user_data_function)
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "type", type);
- if (key && type && switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, NULL, params) == SWITCH_STATUS_SUCCESS) {
+ if (key && type && switch_xml_locate_user("id", user, domain, NULL, &xml, &x_domain, &x_user, &x_group, params) == SWITCH_STATUS_SUCCESS) {
if (!strcmp(type, "attr")) {
const char *attr = switch_xml_attr_soft(x_user, key);
- stream->write_function(stream, "%s", attr);
+ result = attr;
goto end;
}
@@ -649,33 +653,45 @@ SWITCH_STANDARD_API(user_data_function)
elem = "variable";
}
- if ((x_params = switch_xml_child(x_user, container))) {
- for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
- const char *var = switch_xml_attr(x_param, "name");
- const char *val = switch_xml_attr(x_param, "value");
-
- if (var && val && !strcasecmp(var, key)) {
- stream->write_function(stream, "%s", val);
- goto end;
- }
-
- }
- }
-
if ((x_params = switch_xml_child(x_domain, container))) {
for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
const char *var = switch_xml_attr(x_param, "name");
const char *val = switch_xml_attr(x_param, "value");
if (var && val && !strcasecmp(var, key)) {
- stream->write_function(stream, "%s", val);
- goto end;
+ result = val;
+ }
+
+ }
+ }
+
+ if (x_group && (x_params = switch_xml_child(x_group, container))) {
+ for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
+ const char *var = switch_xml_attr(x_param, "name");
+ const char *val = switch_xml_attr(x_param, "value");
+
+ if (var && val && !strcasecmp(var, key)) {
+ result = val;
+ }
+ }
+ }
+
+ if ((x_params = switch_xml_child(x_user, container))) {
+ for (x_param = switch_xml_child(x_params, elem); x_param; x_param = x_param->next) {
+ const char *var = switch_xml_attr(x_param, "name");
+ const char *val = switch_xml_attr(x_param, "value");
+
+ if (var && val && !strcasecmp(var, key)) {
+ result = val;
}
}
}
}
end:
+ if (result) {
+ stream->write_function(stream, "%s", result);
+ }
switch_xml_free(xml);
switch_safe_free(mydata);
switch_event_destroy(¶ms);
@@ -1049,7 +1065,7 @@ SWITCH_STANDARD_API(url_encode_function)
int len = 0;
if (!zstr(cmd)) {
- len = (strlen(cmd) * 3) + 1;
+ len = (int)(strlen(cmd) * 3) + 1;
switch_zmalloc(data, len);
switch_url_encode(cmd, data, len);
reply = data;
@@ -1166,17 +1182,18 @@ SWITCH_STANDARD_API(xml_locate_function)
SWITCH_STANDARD_API(reload_acl_function)
{
const char *err;
- switch_xml_t xml_root;
- if (cmd && !strcmp(cmd, "reloadxml")) {
- if ((xml_root = switch_xml_open_root(1, &err))) {
- switch_xml_free(xml_root);
- }
+ if (cmd && !strcasecmp(cmd, "reloadxml")) {
+ stream->write_function(stream, "This option is deprecated, we now always reloadxml.\n");
+ }
+
+ if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+ switch_load_network_lists(SWITCH_TRUE);
+ stream->write_function(stream, "+OK acl reloaded\n");
+ } else {
+ stream->write_function(stream, "-Error [%s]\n", err);
}
- switch_load_network_lists(SWITCH_TRUE);
-
- stream->write_function(stream, "+OK acl reloaded\n");
return SWITCH_STATUS_SUCCESS;
}
@@ -1374,7 +1391,7 @@ SWITCH_STANDARD_API(cond_function)
argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
- if (argc != 3) {
+ if (! (argc >= 2 && argc <= 3)) {
goto error;
}
@@ -1451,7 +1468,12 @@ SWITCH_STANDARD_API(cond_function)
}
switch_safe_free(s_a);
switch_safe_free(s_b);
- stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]);
+
+ if ((argc == 2 && !is_true)) {
+ stream->write_function(stream, "");
+ } else {
+ stream->write_function(stream, "%s", is_true ? argv[1] : argv[2]);
+ }
goto ok;
}
@@ -1720,6 +1742,10 @@ SWITCH_STANDARD_API(load_function)
return SWITCH_STATUS_SUCCESS;
}
+ if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "+OK Reloading XML\n");
+ }
+
if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK\n");
} else {
@@ -1814,6 +1840,10 @@ SWITCH_STANDARD_API(reload_function)
stream->write_function(stream, "-ERR unloading module [%s]\n", err);
}
+ if (switch_xml_reload(&err) == SWITCH_STATUS_SUCCESS) {
+ stream->write_function(stream, "+OK Reloading XML\n");
+ }
+
if (switch_loadable_module_load_module((char *) SWITCH_GLOBAL_dirs.mod_dir, (char *) cmd, SWITCH_TRUE, &err) == SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "+OK module loaded\n");
} else {
@@ -1825,13 +1855,9 @@ SWITCH_STANDARD_API(reload_function)
SWITCH_STANDARD_API(reload_xml_function)
{
- const char *err;
- switch_xml_t xml_root;
-
- if ((xml_root = switch_xml_open_root(1, &err))) {
- switch_xml_free(xml_root);
- }
+ const char *err = "";
+ switch_xml_reload(&err);
stream->write_function(stream, "+OK [%s]\n", err);
return SWITCH_STATUS_SUCCESS;
@@ -3022,7 +3048,7 @@ SWITCH_STANDARD_API(xml_wrap_api_function)
if (mystream.data) {
if (encoded) {
- elen = (int) strlen(mystream.data) * 3;
+ elen = (int) strlen(mystream.data) * 3 + 1;
edata = malloc(elen);
switch_assert(edata != NULL);
memset(edata, 0, elen);
@@ -4040,7 +4066,7 @@ SWITCH_STANDARD_API(uuid_dump_function)
return SWITCH_STATUS_SUCCESS;
}
-#define GLOBAL_SETVAR_SYNTAX " []"
+#define GLOBAL_SETVAR_SYNTAX "= [=]"
SWITCH_STANDARD_API(global_setvar_function)
{
char *mycmd = NULL, *argv[3] = { 0 };
@@ -4192,7 +4218,7 @@ SWITCH_STANDARD_API(escape_function)
return SWITCH_STATUS_SUCCESS;
}
- len = strlen(cmd) * 2;
+ len = (int)strlen(cmd) * 2;
mycmd = malloc(len);
stream->write_function(stream, "%s", switch_escape_string(cmd, mycmd, len));
@@ -4551,7 +4577,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "originate", "Originate a Call", originate_function, ORIGINATE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "pause", "Pause", pause_function, PAUSE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "regex", "Eval a regex", regex_function, "|[|]");
- SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]");
+ SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "");
SWITCH_ADD_API(commands_api_interface, "reload", "Reload Module", reload_function, UNLOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
SWITCH_ADD_API(commands_api_interface, "replace", "replace a string", replace_function, "||");
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 5128e3baed..7018294546 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -99,7 +99,7 @@ typedef enum {
CALLER_CONTROL_DEAF_MUTE,
CALLER_CONTROL_ENERGY_UP,
CALLER_CONTROL_ENERGY_EQU_CONF,
- CALLER_CONTROL_ENERGEY_DN,
+ CALLER_CONTROL_ENERGY_DN,
CALLER_CONTROL_VOL_TALK_UP,
CALLER_CONTROL_VOL_TALK_ZERO,
CALLER_CONTROL_VOL_TALK_DN,
@@ -121,7 +121,7 @@ typedef struct conference_member conference_member_t;
struct call_list {
char *string;
- int itteration;
+ int iteration;
struct call_list *next;
};
typedef struct call_list call_list_t;
@@ -717,7 +717,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
if (call_list) {
char saymsg[1024];
- switch_snprintf(saymsg, sizeof(saymsg), "Auto Calling %d parties", call_list->itteration);
+ switch_snprintf(saymsg, sizeof(saymsg), "Auto Calling %d parties", call_list->iteration);
conference_member_say(member, saymsg, 0);
} else {
if (zstr(conference->special_announce)) {
@@ -1012,7 +1012,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
uint8_t *file_frame;
uint8_t *async_file_frame;
int16_t *bptr;
- int x = 0;
+ uint32_t x = 0;
int32_t z = 0;
int member_score_sum = 0;
int divisor = 0;
@@ -2298,7 +2298,7 @@ static caller_control_fn_table_t ccfntbl[] = {
{"deaf mute", "*", CALLER_CONTROL_DEAF_MUTE, conference_loop_fn_deafmute_toggle},
{"energy up", "9", CALLER_CONTROL_ENERGY_UP, conference_loop_fn_energy_up},
{"energy equ", "8", CALLER_CONTROL_ENERGY_EQU_CONF, conference_loop_fn_energy_equ_conf},
- {"energy dn", "7", CALLER_CONTROL_ENERGEY_DN, conference_loop_fn_energy_dn},
+ {"energy dn", "7", CALLER_CONTROL_ENERGY_DN, conference_loop_fn_energy_dn},
{"vol talk up", "3", CALLER_CONTROL_VOL_TALK_UP, conference_loop_fn_volume_talk_up},
{"vol talk zero", "2", CALLER_CONTROL_VOL_TALK_ZERO, conference_loop_fn_volume_talk_zero},
{"vol talk dn", "1", CALLER_CONTROL_VOL_TALK_DN, conference_loop_fn_volume_talk_dn},
@@ -3733,7 +3733,7 @@ static switch_status_t conf_api_sub_list(conference_obj_t *conference, switch_st
static switch_xml_t add_x_tag(switch_xml_t x_member, const char *name, const char *value, int off)
{
- switch_size_t dlen = strlen(value) * 3;
+ switch_size_t dlen = strlen(value) * 3 + 1;
char *data;
switch_xml_t x_tag;
@@ -5199,9 +5199,9 @@ SWITCH_STANDARD_APP(conference_auto_function)
np->string = switch_core_session_strdup(session, data);
if (call_list) {
np->next = call_list;
- np->itteration = call_list->itteration + 1;
+ np->iteration = call_list->iteration + 1;
} else {
- np->itteration = 1;
+ np->iteration = 1;
}
call_list = np;
}
diff --git a/src/mod/applications/mod_directory/mod_directory.c b/src/mod/applications/mod_directory/mod_directory.c
index d3389ab3b1..d92974766d 100644
--- a/src/mod/applications/mod_directory/mod_directory.c
+++ b/src/mod/applications/mod_directory/mod_directory.c
@@ -393,7 +393,7 @@ static dir_profile_t *load_profile(const char *profile_name)
profile_set_config(profile);
/* Add the params to the event structure */
- count = switch_event_import_xml(switch_xml_child(x_profile, "param"), "name", "value", &event);
+ count = (int)switch_event_import_xml(switch_xml_child(x_profile, "param"), "name", "value", &event);
if (switch_xml_config_parse_event(event, count, SWITCH_FALSE, profile->config) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to process configuration\n");
@@ -611,7 +611,7 @@ static switch_status_t on_dtmf(switch_core_session_t *session, void *input, swit
}
if (strlen(cbr->digits) < sizeof(cbr->digits) - 2) {
- int at = strlen(cbr->digits);
+ int at = (int)strlen(cbr->digits);
cbr->digits[at++] = dtmf->digit;
cbr->digits[at] = '\0';
} else {
@@ -649,25 +649,25 @@ static switch_status_t listen_entry(switch_core_session_t *session, dir_profile_
if (zstr_buf(buf)) {
switch_snprintf(macro, sizeof(macro), "phrase:%s:%d", DIR_RESULT_ITEM, cbt->want + 1);
- switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+ switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
}
if (!zstr_buf(recorded_name) && zstr_buf(buf)) {
- switch_ivr_read(session, 0, 1, recorded_name, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+ switch_ivr_read(session, 0, 1, recorded_name, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
}
if (zstr_buf(recorded_name) && zstr_buf(buf)) {
switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", DIR_RESULT_SAY_NAME, cbt->fullname);
- switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+ switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
}
if (cbt->exten_visible && zstr_buf(buf)) {
switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", DIR_RESULT_AT, cbt->extension);
- switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key);
+ switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), 1, profile->terminator_key, 0);
}
if (zstr_buf(buf)) {
switch_snprintf(macro, sizeof(macro), "phrase:%s:%c,%c,%c,%c", DIR_RESULT_MENU, *profile->select_name_key, *profile->next_key, *profile->prev_key,
*profile->new_search_key);
- switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), profile->digit_timeout, profile->terminator_key);
+ switch_ivr_read(session, 0, 1, macro, NULL, buf, sizeof(buf), profile->digit_timeout, profile->terminator_key, 0);
}
if (!zstr_buf(buf)) {
@@ -884,6 +884,18 @@ SWITCH_STANDARD_APP(directory_function)
if (strcasecmp(profile->search_order, "last_name")) {
s_param.search_by_last_name = 0;
}
+
+ {
+ const char *var_search_order = switch_channel_get_variable(channel, "directory_search_order");
+ if (var_search_order) {
+ if (!strcasecmp(var_search_order, "first_name")) {
+ s_param.search_by_last_name = 0;
+ } else {
+ s_param.search_by_last_name = 1;
+ }
+ }
+ }
+
attempts = profile->max_menu_attempt;
s_param.try_again = 1;
while (switch_channel_ready(channel) && (s_param.try_again && attempts-- > 0)) {
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 55429275dd..dd63f8aae9 100755
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -1712,10 +1712,11 @@ SWITCH_STANDARD_APP(att_xfer_function)
SWITCH_STANDARD_APP(read_function)
{
char *mydata;
- char *argv[6] = { 0 };
+ char *argv[7] = { 0 };
int argc;
int32_t min_digits = 0;
int32_t max_digits = 0;
+ uint32_t digit_timeout = 0;
int timeout = 1000;
char digit_buffer[128] = "";
const char *prompt_audio_file = NULL;
@@ -1751,6 +1752,13 @@ SWITCH_STANDARD_APP(read_function)
valid_terminators = argv[5];
}
+ if (argc > 6) {
+ digit_timeout = atoi(argv[6]);
+ if (digit_timeout < 0) {
+ digit_timeout = 0;
+ }
+ }
+
if (min_digits <= 1) {
min_digits = 1;
}
@@ -1767,17 +1775,19 @@ SWITCH_STANDARD_APP(read_function)
valid_terminators = "#";
}
- switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name, digit_buffer, sizeof(digit_buffer), timeout, valid_terminators);
+ switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name, digit_buffer, sizeof(digit_buffer), timeout, valid_terminators,
+ digit_timeout);
}
SWITCH_STANDARD_APP(play_and_get_digits_function)
{
char *mydata;
- char *argv[9] = { 0 };
+ char *argv[10] = { 0 };
int argc;
int32_t min_digits = 0;
int32_t max_digits = 0;
int32_t max_tries = 0;
+ uint32_t digit_timeout = 0;
int timeout = 1000;
char digit_buffer[128] = "";
const char *prompt_audio_file = NULL;
@@ -1827,6 +1837,14 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
digits_regex = argv[8];
}
+ if (argc > 9) {
+ digit_timeout = atoi(argv[9]);
+ if (digit_timeout < 0) {
+ digit_timeout = 0;
+ }
+ }
+
+
if (min_digits <= 1) {
min_digits = 1;
}
@@ -1844,7 +1862,7 @@ SWITCH_STANDARD_APP(play_and_get_digits_function)
}
switch_play_and_get_digits(session, min_digits, max_digits, max_tries, timeout, valid_terminators,
- prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex);
+ prompt_audio_file, bad_input_audio_file, var_name, digit_buffer, sizeof(digit_buffer), digits_regex, digit_timeout);
}
#define SAY_SYNTAX " [] "
@@ -3367,9 +3385,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
SWITCH_ADD_APP(app_interface, "endless_playback", "Playback File Endlessly", "Endlessly Playback a file to the channel",
endless_playback_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "att_xfer", "Attended Transfer", "Attended Transfer", att_xfer_function, "", SAF_NONE);
- SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function, " ", SAF_NONE);
+ SWITCH_ADD_APP(app_interface, "read", "Read Digits", "Read Digits", read_function,
+ " ", SAF_NONE);
SWITCH_ADD_APP(app_interface, "play_and_get_digits", "Play and get Digits", "Play and get Digits",
- play_and_get_digits_function, " ", SAF_NONE);
+ play_and_get_digits_function,
+ " []", SAF_NONE);
SWITCH_ADD_APP(app_interface, "stop_record_session", "Stop Record Session", STOP_SESS_REC_DESC, stop_record_session_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, " [+]", SAF_MEDIA_TAP);
SWITCH_ADD_APP(app_interface, "record", "Record File", "Record a file from the channels input", record_function,
diff --git a/src/mod/applications/mod_fifo/mod_fifo.c b/src/mod/applications/mod_fifo/mod_fifo.c
index aa49689062..563706c9f2 100644
--- a/src/mod/applications/mod_fifo/mod_fifo.c
+++ b/src/mod/applications/mod_fifo/mod_fifo.c
@@ -439,7 +439,7 @@ static switch_status_t moh_on_dtmf(switch_core_session_t *session, void *input,
#define check_string(s) if (!zstr(s) && !strcasecmp(s, "undef")) { s = NULL; }
-static int node_consumer_wait_count(fifo_node_t *node)
+static int node_caller_count(fifo_node_t *node)
{
int i, len = 0;
@@ -458,7 +458,7 @@ static void node_remove_uuid(fifo_node_t *node, const char *uuid)
fifo_queue_popfly(node->fifo_list[i], uuid);
}
- if (!node_consumer_wait_count(node)) {
+ if (!node_caller_count(node)) {
node->start_waiting = 0;
}
@@ -513,7 +513,6 @@ static switch_status_t caller_read_frame_callback(switch_core_session_t *session
if (match_key(caller_exit_key, *buf)) {
cd->abort = 1;
return SWITCH_STATUS_FALSE;
- switch_channel_set_variable(channel, "fifo_caller_exit_key", (char *)buf);
}
cd->next = switch_epoch_time_now(NULL) + cd->freq;
cd->index++;
@@ -875,7 +874,7 @@ static void do_unbridge(switch_core_session_t *consumer_session, switch_core_ses
char *sql;
switch_event_t *event;
- switch_channel_clear_app_flag(consumer_channel, FIFO_APP_BRIDGE_TAG);
+ switch_channel_clear_app_flag_key(__FILE__, consumer_channel, FIFO_APP_BRIDGE_TAG);
switch_channel_set_variable(consumer_channel, "fifo_bridged", NULL);
ts = switch_micro_time_now();
@@ -989,7 +988,7 @@ static switch_status_t messagehook (switch_core_session_t *session, switch_core_
goto end;
}
- switch_channel_set_app_flag(consumer_channel, FIFO_APP_BRIDGE_TAG);
+ switch_channel_set_app_flag_key(__FILE__, consumer_channel, FIFO_APP_BRIDGE_TAG);
switch_channel_set_variable(consumer_channel, "fifo_bridged", "true");
switch_channel_set_variable(consumer_channel, "fifo_manual_bridge", "true");
@@ -1683,7 +1682,7 @@ static void find_consumers(fifo_node_t *node)
switch(node->outbound_strategy) {
case NODE_STRATEGY_ENTERPRISE:
{
- int need = node_consumer_wait_count(node);
+ int need = node_caller_count(node);
if (node->outbound_per_cycle && node->outbound_per_cycle < need) {
need = node->outbound_per_cycle;
@@ -1753,7 +1752,7 @@ static void *SWITCH_THREAD_FUNC node_thread_run(switch_thread_t *thread, void *o
if ((node = (fifo_node_t *) val)) {
if (node->outbound_priority == 0) node->outbound_priority = 5;
if (node->has_outbound && node->ready && !node->busy && node->outbound_priority == cur_priority) {
- ppl_waiting = node_consumer_wait_count(node);
+ ppl_waiting = node_caller_count(node);
consumer_total = node->consumer_count;
idle_consumers = node_idle_consumers(node);
@@ -1831,7 +1830,7 @@ static void check_cancel(fifo_node_t *node)
return;
}
- ppl_waiting = node_consumer_wait_count(node);
+ ppl_waiting = node_caller_count(node);
if (node->ring_consumer_count > 0 && ppl_waiting < 1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Outbound call count (%d) exceeds required value for queue %s (%d), "
@@ -1855,7 +1854,7 @@ static void send_presence(fifo_node_t *node)
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", "park");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", node->name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", node->name);
- if ((wait_count = node_consumer_wait_count(node)) > 0) {
+ if ((wait_count = node_caller_count(node)) > 0) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Active (%d waiting)", wait_count);
} else {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", "Idle");
@@ -1990,6 +1989,11 @@ static void dec_use_count(switch_core_session_t *session, switch_bool_t send_eve
if ((outbound_id = switch_channel_get_variable(channel, "fifo_outbound_uuid"))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s untracking call on uuid %s!\n", switch_channel_get_name(channel), outbound_id);
+
+ sql = switch_mprintf("delete from fifo_bridge where consumer_uuid='%q'", switch_core_session_get_uuid(session));
+ fifo_execute_sql(sql, globals.sql_mutex);
+ switch_safe_free(sql);
+
del_bridge_call(outbound_id);
sql = switch_mprintf("update fifo_outbound set use_count=use_count-1, stop_time=%ld, next_avail=%ld + lag + 1 where use_count > 0 and uuid='%q'",
now, now, outbound_id);
@@ -2043,7 +2047,7 @@ SWITCH_STANDARD_APP(fifo_track_call_function)
add_bridge_call(data);
- switch_channel_set_app_flag(channel, FIFO_APP_TRACKING);
+ switch_channel_set_app_flag_key(__FILE__, channel, FIFO_APP_TRACKING);
switch_channel_set_variable(channel, "fifo_outbound_uuid", data);
switch_channel_set_variable(channel, "fifo_track_call", "true");
@@ -2296,7 +2300,6 @@ SWITCH_STANDARD_APP(fifo_function)
switch_channel_answer(channel);
switch_thread_rwlock_wrlock(node->rwlock);
- node->caller_count++;
if ((pri = switch_channel_get_variable(channel, "fifo_priority"))) {
p = atoi(pri);
@@ -2306,7 +2309,7 @@ SWITCH_STANDARD_APP(fifo_function)
p = MAX_PRI - 1;
}
- if (!node_consumer_wait_count(node)) {
+ if (!node_caller_count(node)) {
node->start_waiting = switch_micro_time_now();
}
@@ -2343,7 +2346,7 @@ SWITCH_STANDARD_APP(fifo_function)
switch_channel_set_variable(channel, "fifo_timestamp", date);
switch_channel_set_variable(channel, "fifo_serviced_uuid", NULL);
- switch_channel_set_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+ switch_channel_set_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
if (chime_list) {
char *list_dup = switch_core_session_strdup(session, chime_list);
@@ -2416,10 +2419,10 @@ SWITCH_STANDARD_APP(fifo_function)
}
}
- switch_channel_clear_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+ abort:
+
+ switch_channel_clear_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
- abort:
-
fifo_caller_del(switch_core_session_get_uuid(session));
if (!aborted && switch_channel_ready(channel)) {
@@ -2442,7 +2445,6 @@ SWITCH_STANDARD_APP(fifo_function)
switch_mutex_lock(globals.mutex);
switch_thread_rwlock_wrlock(node->rwlock);
node_remove_uuid(node, uuid);
- node->caller_count--;
switch_thread_rwlock_unlock(node->rwlock);
send_presence(node);
check_cancel(node);
@@ -2583,7 +2585,7 @@ SWITCH_STANDARD_APP(fifo_function)
continue;
}
- if ((waiting = node_consumer_wait_count(node))) {
+ if ((waiting = node_caller_count(node))) {
if (!importance || node->importance > importance) {
if (strat == STRAT_WAITING_LONGER) {
@@ -2671,7 +2673,7 @@ SWITCH_STANDARD_APP(fifo_function)
}
}
- if (pop && !node_consumer_wait_count(node)) {
+ if (pop && !node_caller_count(node)) {
switch_thread_rwlock_wrlock(node->rwlock);
node->start_waiting = 0;
switch_thread_rwlock_unlock(node->rwlock);
@@ -2775,7 +2777,8 @@ SWITCH_STANDARD_APP(fifo_function)
switch_channel_set_flag(other_channel, CF_BREAK);
- while (switch_channel_ready(channel) && switch_channel_ready(other_channel) && switch_channel_test_app_flag(other_channel, FIFO_APP_BRIDGE_TAG)) {
+ while (switch_channel_ready(channel) && switch_channel_ready(other_channel) &&
+ switch_channel_test_app_flag(other_channel, FIFO_APP_BRIDGE_TAG)) {
status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
break;
@@ -2787,9 +2790,6 @@ SWITCH_STANDARD_APP(fifo_function)
const char *arg = switch_channel_get_variable(other_channel, "current_application_data");
switch_caller_extension_t *extension = NULL;
- switch_thread_rwlock_wrlock(node->rwlock);
- node->caller_count--;
- switch_thread_rwlock_unlock(node->rwlock);
send_presence(node);
check_cancel(node);
@@ -2955,9 +2955,6 @@ SWITCH_STANDARD_APP(fifo_function)
switch_channel_set_variable(other_channel, "fifo_status", "DONE");
switch_channel_set_variable(other_channel, "fifo_timestamp", date);
- switch_thread_rwlock_wrlock(node->rwlock);
- node->caller_count--;
- switch_thread_rwlock_unlock(node->rwlock);
send_presence(node);
check_cancel(node);
switch_core_session_rwunlock(other_session);
@@ -3070,7 +3067,7 @@ SWITCH_STANDARD_APP(fifo_function)
done:
switch_mutex_lock(globals.mutex);
- if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node->caller_count == 0) {
+ if (node && node->ready == FIFO_DELAY_DESTROY && node->consumer_count == 0 && node_caller_count(node) == 0) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "%s removed.\n", node->name);
switch_core_hash_delete(globals.fifo_hash, node->name);
switch_thread_rwlock_wrlock(node->rwlock);
@@ -3085,7 +3082,7 @@ SWITCH_STANDARD_APP(fifo_function)
switch_mutex_unlock(globals.mutex);
- switch_channel_clear_app_flag(channel, FIFO_APP_BRIDGE_TAG);
+ switch_channel_clear_app_flag_key(__FILE__, channel, FIFO_APP_BRIDGE_TAG);
switch_core_media_bug_resume(session);
@@ -3505,9 +3502,9 @@ static void list_node(fifo_node_t *node, switch_xml_t x_report, int *off, int ve
switch_xml_set_attr_d(x_fifo, "name", node->name);
switch_snprintf(tmp, sizeof(buffer), "%d", node->consumer_count);
switch_xml_set_attr_d(x_fifo, "consumer_count", tmp);
- switch_snprintf(tmp, sizeof(buffer), "%d", node->caller_count);
+ switch_snprintf(tmp, sizeof(buffer), "%d", node_caller_count(node));
switch_xml_set_attr_d(x_fifo, "caller_count", tmp);
- switch_snprintf(tmp, sizeof(buffer), "%d", node_consumer_wait_count(node));
+ switch_snprintf(tmp, sizeof(buffer), "%d", node_caller_count(node));
switch_xml_set_attr_d(x_fifo, "waiting_count", tmp);
switch_snprintf(tmp, sizeof(buffer), "%u", node->importance);
switch_xml_set_attr_d(x_fifo, "importance", tmp);
@@ -3569,7 +3566,7 @@ void node_dump(switch_stream_handle_t *stream)
node->outbound_priority,
node->busy,
node->ready,
- node_consumer_wait_count(node)
+ node_caller_count(node)
);
}
@@ -3687,9 +3684,9 @@ SWITCH_STANDARD_API(fifo_api_function)
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, &var, NULL, &val);
node = (fifo_node_t *) val;
- len = node_consumer_wait_count(node);
+ len = node_caller_count(node);
switch_thread_rwlock_wrlock(node->rwlock);
- stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node->caller_count, len);
+ stream->write_function(stream, "%s:%d:%d:%d\n", (char *) var, node->consumer_count, node_caller_count(node), len);
switch_thread_rwlock_unlock(node->rwlock);
x++;
}
@@ -3698,9 +3695,9 @@ SWITCH_STANDARD_API(fifo_api_function)
stream->write_function(stream, "none\n");
}
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
- len = node_consumer_wait_count(node);
+ len = node_caller_count(node);
switch_thread_rwlock_wrlock(node->rwlock);
- stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node->caller_count, len);
+ stream->write_function(stream, "%s:%d:%d:%d\n", argv[1], node->consumer_count, node_caller_count(node), len);
switch_thread_rwlock_unlock(node->rwlock);
} else {
stream->write_function(stream, "none\n");
@@ -3710,7 +3707,7 @@ SWITCH_STANDARD_API(fifo_api_function)
for (hi = switch_hash_first(NULL, globals.fifo_hash); hi; hi = switch_hash_next(hi)) {
switch_hash_this(hi, &var, NULL, &val);
node = (fifo_node_t *) val;
- len = node_consumer_wait_count(node);
+ len = node_caller_count(node);
switch_thread_rwlock_wrlock(node->rwlock);
stream->write_function(stream, "%s:%d\n", (char *) var, node->has_outbound);
switch_thread_rwlock_unlock(node->rwlock);
@@ -3721,7 +3718,7 @@ SWITCH_STANDARD_API(fifo_api_function)
stream->write_function(stream, "none\n");
}
} else if ((node = switch_core_hash_find(globals.fifo_hash, argv[1]))) {
- len = node_consumer_wait_count(node);
+ len = node_caller_count(node);
switch_thread_rwlock_wrlock(node->rwlock);
stream->write_function(stream, "%s:%d\n", argv[1], node->has_outbound);
switch_thread_rwlock_unlock(node->rwlock);
@@ -4072,7 +4069,7 @@ static switch_status_t load_config(int reload, int del_all)
continue;
}
- if (node_consumer_wait_count(node) || node->consumer_count || node_idle_consumers(node)) {
+ if (node_caller_count(node) || node->consumer_count || node_idle_consumers(node)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s removal delayed, still in use.\n", node->name);
node->ready = FIFO_DELAY_DESTROY;
} else {
diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c
index 3a65528ea3..29a056104f 100644
--- a/src/mod/applications/mod_hash/mod_hash.c
+++ b/src/mod/applications/mod_hash/mod_hash.c
@@ -852,7 +852,8 @@ static void do_config(switch_bool_t reload)
const char *username = switch_xml_attr(x_list, "username");
const char *password = switch_xml_attr(x_list, "password");
const char *szinterval = switch_xml_attr(x_list, "interval");
- int port = 0, interval = 0;
+ uint16_t port = 0;
+ int interval = 0;
limit_remote_t *remote;
switch_threadattr_t *thd_attr = NULL;
@@ -866,7 +867,7 @@ static void do_config(switch_bool_t reload)
}
if (!zstr(szport)) {
- port = atoi(szport);
+ port = (uint16_t)atoi(szport);
}
if (!zstr(szinterval)) {
@@ -949,7 +950,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)
/* Kill remote connections, destroy needs a wrlock so we unlock after finding a pointer */
while(remote_clean) {
void *val;
- const void *key;
+ const void *key = NULL;
switch_ssize_t keylen;
limit_remote_t *item = NULL;
diff --git a/src/mod/applications/mod_lcr/mod_lcr.c b/src/mod/applications/mod_lcr/mod_lcr.c
index bbf7bb568d..cc93707367 100644
--- a/src/mod/applications/mod_lcr/mod_lcr.c
+++ b/src/mod/applications/mod_lcr/mod_lcr.c
@@ -167,7 +167,7 @@ static const char *do_cid(switch_memory_pool_t *pool, const char *cid, const cha
switch_channel_t *channel = NULL;
if (!zstr(cid)) {
- len = strlen(cid);
+ len = (uint32_t)strlen(cid);
} else {
goto done;
}
@@ -506,7 +506,7 @@ static char *expand_digits(switch_memory_pool_t *pool, char *digits, switch_bool
int digit_len;
SWITCH_STANDARD_STREAM(dig_stream);
- digit_len = strlen(digits);
+ digit_len = (int)strlen(digits);
digits_copy = switch_core_strdup(pool, digits);
for (n = digit_len; n > 0; n--) {
@@ -1571,7 +1571,6 @@ SWITCH_STANDARD_APP(lcr_app_function)
switch_channel_set_variable(channel, vbuf, cur_route->carrier_name);
switch_snprintf(vbuf, sizeof(vbuf), "lcr_codec_%d", cnt);
switch_channel_set_variable(channel, vbuf, cur_route->codec);
- cnt++;
if (cur_route->next) {
if (routes.profile->enable_sip_redir) {
dig_stream.write_function(&dig_stream, "%s,", cur_route->dialstring);
diff --git a/src/mod/applications/mod_nibblebill/mod_nibblebill.c b/src/mod/applications/mod_nibblebill/mod_nibblebill.c
index 06bc7d0abd..42369f5d0b 100755
--- a/src/mod/applications/mod_nibblebill/mod_nibblebill.c
+++ b/src/mod/applications/mod_nibblebill/mod_nibblebill.c
@@ -419,10 +419,10 @@ static switch_status_t do_billing(switch_core_session_t *session)
billaccount = switch_channel_get_variable(channel, "nibble_account");
if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
- nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt"));
+ nobal_amt = (float)atof(switch_channel_get_variable(channel, "nobal_amt"));
}
if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) {
- lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
+ lowbal_amt = (float)atof(switch_channel_get_variable(channel, "lowbal_amt"));
}
/* Return if there's no billing information on this session */
diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
index 096d967ff0..aa7d05cf9e 100644
--- a/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
+++ b/src/mod/applications/mod_spandsp/mod_spandsp_dsp.c
@@ -549,8 +549,8 @@ static switch_status_t do_config(void)
if (id == -1) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to add tone_descriptor: %s, tone: %s. (too many tones)\n", name, tone_name);
return SWITCH_STATUS_FALSE;
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);}
+ }
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Adding tone_descriptor: %s, tone: %s(%d)\n", name, tone_name, id);
/* add elements to tone */
for (element = switch_xml_child(tone, "element"); element; element = switch_xml_next(element)) {
const char *freq1_attr = switch_xml_attr(element, "freq1");
diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
index 7ff106aceb..27878246f0 100644
--- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
+++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c
@@ -74,6 +74,8 @@ static struct {
char header[50];
char *prepend_string;
char *spool;
+ switch_thread_cond_t *cond;
+ switch_mutex_t *cond_mutex;
} globals;
struct pvt_s {
@@ -118,27 +120,34 @@ static struct {
int thread_running;
} t38_state_list;
+
+
+static void wake_thread(int force)
+{
+ if (force) {
+ switch_thread_cond_signal(globals.cond);
+ return;
+ }
+
+ if (switch_mutex_trylock(globals.cond_mutex) == SWITCH_STATUS_SUCCESS) {
+ switch_thread_cond_signal(globals.cond);
+ switch_mutex_unlock(globals.cond_mutex);
+ }
+}
+
static int add_pvt(pvt_t *pvt)
{
int r = 0;
- uint32_t sanity = 50;
-
- switch_mutex_lock(t38_state_list.mutex);
- if (!t38_state_list.thread_running) {
-
- launch_timer_thread();
-
- while(--sanity && !t38_state_list.thread_running) {
- switch_yield(10000);
- }
- }
- switch_mutex_unlock(t38_state_list.mutex);
if (t38_state_list.thread_running) {
switch_mutex_lock(t38_state_list.mutex);
pvt->next = t38_state_list.head;
t38_state_list.head = pvt;
switch_mutex_unlock(t38_state_list.mutex);
+ r = 1;
+ wake_thread(0);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error launching thread\n");
}
return r;
@@ -151,9 +160,9 @@ static int del_pvt(pvt_t *del_pvt)
pvt_t *p, *l = NULL;
int r = 0;
- if (!t38_state_list.thread_running) goto end;
-
+
switch_mutex_lock(t38_state_list.mutex);
+
for (p = t38_state_list.head; p; p = p->next) {
if (p == del_pvt) {
if (l) {
@@ -163,34 +172,38 @@ static int del_pvt(pvt_t *del_pvt)
}
p->next = NULL;
r = 1;
- goto end;
+ break;
}
l = p;
}
- end:
-
switch_mutex_unlock(t38_state_list.mutex);
- return r;
+ wake_thread(0);
+ return r;
}
static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *obj)
{
switch_timer_t timer = { 0 };
pvt_t *pvt;
- int samples = 240;
- int ms = 30;
+ int samples = 160;
+ int ms = 20;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread started.\n");
+ switch_mutex_lock(t38_state_list.mutex);
+ t38_state_list.thread_running = 1;
+ switch_mutex_unlock(t38_state_list.mutex);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread started.\n");
if (switch_core_timer_init(&timer, "soft", ms, samples, NULL) != SWITCH_STATUS_SUCCESS) {
- return NULL;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "timer init failed.\n");
+ goto end;
}
- t38_state_list.thread_running = 1;
+ switch_mutex_lock(globals.cond_mutex);
while(t38_state_list.thread_running) {
@@ -198,7 +211,9 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
if (!t38_state_list.head) {
switch_mutex_unlock(t38_state_list.mutex);
- goto end;
+ switch_thread_cond_wait(globals.cond, globals.cond_mutex);
+ switch_core_timer_sync(&timer);
+ continue;
}
for (pvt = t38_state_list.head; pvt; pvt = pvt->next) {
@@ -211,13 +226,20 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *
switch_core_timer_next(&timer);
}
+
+ switch_mutex_unlock(globals.cond_mutex);
end:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread ended.\n");
-
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread ended.\n");
+
+ switch_mutex_lock(t38_state_list.mutex);
t38_state_list.thread_running = 0;
- switch_core_timer_destroy(&timer);
+ switch_mutex_unlock(t38_state_list.mutex);
+
+ if (timer.timer_interface) {
+ switch_core_timer_destroy(&timer);
+ }
return NULL;
}
@@ -468,49 +490,61 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
}
break;
case T38_MODE:
- if (pvt->t38_state == NULL) {
- pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t));
- }
- if (pvt->t38_state == NULL) {
- return SWITCH_STATUS_FALSE;
- }
- if (pvt->udptl_state == NULL) {
- pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t));
- }
- if (pvt->udptl_state == NULL) {
- t38_terminal_free(pvt->t38_state);
- pvt->t38_state = NULL;
- return SWITCH_STATUS_FALSE;
- }
+ {
+ switch_core_session_message_t msg = { 0 };
- /* add to timer thread processing */
- add_pvt(pvt);
+ if (pvt->t38_state == NULL) {
+ pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t));
+ }
+ if (pvt->t38_state == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+ if (pvt->udptl_state == NULL) {
+ pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t));
+ }
+ if (pvt->udptl_state == NULL) {
+ t38_terminal_free(pvt->t38_state);
+ pvt->t38_state = NULL;
+ return SWITCH_STATUS_FALSE;
+ }
+
+ t38 = pvt->t38_state;
+ t30 = t38_terminal_get_t30_state(t38);
+
+ memset(t38, 0, sizeof(t38_terminal_state_t));
+
+ if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state);
+
+ if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3,
+ (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ msg.from = __FILE__;
+ msg.message_id = SWITCH_MESSAGE_INDICATE_UDPTL_MODE;
+ switch_core_session_receive_message(pvt->session, &msg);
- t38 = pvt->t38_state;
- t30 = t38_terminal_get_t30_state(t38);
+ /* add to timer thread processing */
+ if (!add_pvt(pvt)) {
+ if (channel) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+ }
+
+ span_log_set_message_handler(&t38->logging, spanfax_log_message);
+ span_log_set_message_handler(&t30->logging, spanfax_log_message);
- memset(t38, 0, sizeof(t38_terminal_state_t));
-
- if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n");
- return SWITCH_STATUS_FALSE;
- }
-
- pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state);
-
- if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3,
- (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n");
- return SWITCH_STATUS_FALSE;
- }
-
- span_log_set_message_handler(&t38->logging, spanfax_log_message);
- span_log_set_message_handler(&t30->logging, spanfax_log_message);
-
- if (pvt->verbose) {
- span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
- }
+ if (pvt->verbose) {
+ span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+ span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
+ }
+ }
break;
case T38_GATEWAY_MODE:
if (pvt->t38_gateway_state == NULL) {
@@ -757,9 +791,9 @@ static t38_mode_t negotiate_t38(pvt_t *pvt)
t38_options->T38FaxRateManagement = "transferredTCF";
t38_options->T38FaxMaxBuffer = 2000;
t38_options->T38FaxMaxDatagram = LOCAL_FAX_MAX_DATAGRAM;
- if (strcasecmp(t38_options->T38FaxUdpEC, "t38UDPRedundancy") == 0
- ||
- strcasecmp(t38_options->T38FaxUdpEC, "t38UDPFEC") == 0) {
+ if (!zstr(t38_options->T38FaxUdpEC) &&
+ (strcasecmp(t38_options->T38FaxUdpEC, "t38UDPRedundancy") == 0 ||
+ strcasecmp(t38_options->T38FaxUdpEC, "t38UDPFEC") == 0)) {
t38_options->T38FaxUdpEC = "t38UDPRedundancy";
} else {
t38_options->T38FaxUdpEC = NULL;
@@ -818,6 +852,12 @@ static t38_mode_t request_t38(pvt_t *pvt)
insist = globals.enable_t38_insist;
}
+ if ((t38_options = switch_channel_get_private(channel, "t38_options"))) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
+ "%s already has T.38 data\n", switch_channel_get_name(channel));
+ enabled = 0;
+ }
+
if (enabled) {
t38_options = switch_core_session_alloc(session, sizeof(*t38_options));
@@ -960,6 +1000,7 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
switch_frame_t write_frame = { 0 };
switch_codec_implementation_t read_impl = { 0 };
int16_t *buf = NULL;
+ uint32_t req_counter = 0;
switch_core_session_get_read_impl(session, &read_impl);
@@ -1075,10 +1116,11 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
switch_ivr_sleep(session, 250, SWITCH_TRUE, NULL);
-
- /* If you have the means, I highly recommend picking one up. ...*/
- request_t38(pvt);
-
+ if (pvt->app_mode == FUNCTION_TX) {
+ req_counter = 100;
+ } else {
+ req_counter = 50;
+ }
while (switch_channel_ready(channel)) {
int tx = 0;
@@ -1122,6 +1164,13 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
break;
case T38_MODE_UNKNOWN:
{
+ if (req_counter) {
+ if (!--req_counter) {
+ /* If you have the means, I highly recommend picking one up. ...*/
+ request_t38(pvt);
+ }
+ }
+
if (switch_channel_test_app_flag_key("T38", channel, CF_APP_T38)) {
if (negotiate_t38(pvt) == T38_MODE_NEGOTIATED) {
/* is is safe to call this again, it was already called above in AUDIO_MODE */
@@ -1145,8 +1194,6 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat
//switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "READ %d udptl bytes\n", read_frame->packetlen);
udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen);
-
-
}
}
continue;
@@ -1282,6 +1329,8 @@ void mod_spandsp_fax_event_handler(switch_event_t *event)
void mod_spandsp_fax_load(switch_memory_pool_t *pool)
{
+ uint32_t sanity = 200;
+
memset(&globals, 0, sizeof(globals));
memset(&t38_state_list, 0, sizeof(t38_state_list));
@@ -1289,6 +1338,9 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+
+ switch_mutex_init(&globals.cond_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+ switch_thread_cond_create(&globals.cond, globals.pool);
globals.enable_t38 = 1;
globals.total_sessions = 0;
@@ -1301,10 +1353,22 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1);
load_configuration(0);
+
+
+ launch_timer_thread();
+
+ while(--sanity && !t38_state_list.thread_running) {
+ switch_yield(20000);
+ }
}
void mod_spandsp_fax_shutdown(void)
{
+ switch_status_t tstatus = SWITCH_STATUS_SUCCESS;
+
+ t38_state_list.thread_running = 0;
+ wake_thread(1);
+ switch_thread_join(&tstatus, t38_state_list.thread);
memset(&globals, 0, sizeof(globals));
}
@@ -1659,8 +1723,8 @@ static switch_status_t t38_gateway_on_reset(switch_core_session_t *session)
switch_channel_clear_flag(channel, CF_REDIRECT);
- if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) {
- switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
+ if (switch_channel_test_app_flag_key("T38", channel, CF_APP_TAGGED)) {
+ switch_channel_clear_app_flag_key("T38", channel, CF_APP_TAGGED);
switch_channel_set_state(channel, CS_CONSUME_MEDIA);
} else {
switch_channel_set_state(channel, CS_SOFT_EXECUTE);
@@ -1697,6 +1761,9 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
switch_channel_set_variable(channel, "t38_peer", switch_core_session_get_uuid(other_session));
switch_channel_set_variable(other_channel, "t38_peer", switch_core_session_get_uuid(session));
+ switch_channel_set_variable(peer ? other_channel : channel, "t38_gateway_format", "audio");
+ switch_channel_set_variable(peer ? channel : other_channel, "t38_gateway_format", "udptl");
+
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s starting gateway mode to %s\n",
switch_channel_get_name(peer ? channel : other_channel),
@@ -1709,8 +1776,8 @@ switch_bool_t t38_gateway_start(switch_core_session_t *session, const char *app,
switch_channel_add_state_handler(channel, &t38_gateway_state_handlers);
switch_channel_add_state_handler(other_channel, &t38_gateway_state_handlers);
- switch_channel_set_app_flag(peer ? channel : other_channel, CF_APP_TAGGED);
- switch_channel_clear_app_flag(peer ? other_channel : channel, CF_APP_TAGGED);
+ switch_channel_set_app_flag_key("T38", peer ? channel : other_channel, CF_APP_TAGGED);
+ switch_channel_clear_app_flag_key("T38", peer ? other_channel : channel, CF_APP_TAGGED);
switch_channel_set_flag(channel, CF_REDIRECT);
switch_channel_set_state(channel, CS_RESET);
diff --git a/src/mod/applications/mod_spandsp/udptl.c b/src/mod/applications/mod_spandsp/udptl.c
index a2651513f0..f5b3be2445 100644
--- a/src/mod/applications/mod_spandsp/udptl.c
+++ b/src/mod/applications/mod_spandsp/udptl.c
@@ -93,7 +93,7 @@ static int encode_length(uint8_t *buf, int *len, int value)
if (value < 0x80) {
/* 1 octet */
- buf[(*len)++] = value;
+ buf[(*len)++] = (uint8_t)value;
return value;
}
if (value < 0x4000) {
@@ -106,7 +106,7 @@ static int encode_length(uint8_t *buf, int *len, int value)
/* Fragmentation */
multiplier = (value < 0x10000) ? (value >> 14) : 4;
/* Set the first 2 bits of the octet */
- buf[(*len)++] = 0xC0 | multiplier;
+ buf[(*len)++] = (uint8_t) (0xC0 | multiplier);
return multiplier << 14;
}
@@ -419,10 +419,10 @@ int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int
/* Span is defined as an inconstrained integer, which it dumb. It will only
ever be a small value. Treat it as such. */
buf[len++] = 1;
- buf[len++] = span;
+ buf[len++] = (uint8_t)span;
/* The number of entries is defined as a length, but will only ever be a small
value. Treat it as such. */
- buf[len++] = entries;
+ buf[len++] = (uint8_t)entries;
for (m = 0; m < entries; m++) {
/* Make an XOR'ed entry the maximum length */
limit = (entry + m) & UDPTL_BUF_MASK;
diff --git a/src/mod/applications/mod_valet_parking/mod_valet_parking.c b/src/mod/applications/mod_valet_parking/mod_valet_parking.c
index aee49c76e9..b75202189c 100644
--- a/src/mod/applications/mod_valet_parking/mod_valet_parking.c
+++ b/src/mod/applications/mod_valet_parking/mod_valet_parking.c
@@ -203,7 +203,7 @@ SWITCH_STANDARD_APP(valet_parking_function)
}
do {
- status = switch_ivr_read(session, min, max, prompt, NULL, dtmf_buf, sizeof(dtmf_buf), to, "#");
+ status = switch_ivr_read(session, min, max, prompt, NULL, dtmf_buf, sizeof(dtmf_buf), to, "#", 0);
} while (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_FALSE);
if (status == SWITCH_STATUS_SUCCESS) {
diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c
index c683712922..860f89788b 100644
--- a/src/mod/applications/mod_voicemail/mod_voicemail.c
+++ b/src/mod/applications/mod_voicemail/mod_voicemail.c
@@ -824,7 +824,8 @@ static switch_status_t control_playback(switch_core_session_t *session, void *in
if (!cc->noexit
&& (dtmf->digit == *cc->profile->delete_file_key || dtmf->digit == *cc->profile->save_file_key
|| dtmf->digit == *cc->profile->prev_msg_key || dtmf->digit == *cc->profile->next_msg_key
- || dtmf->digit == *cc->profile->terminator_key || dtmf->digit == *cc->profile->skip_info_key)) {
+ || dtmf->digit == *cc->profile->terminator_key || dtmf->digit == *cc->profile->skip_info_key
+ || dtmf->digit == *cc->profile->email_key || dtmf->digit == *cc->profile->forward_key)) {
*cc->buf = dtmf->digit;
return SWITCH_STATUS_BREAK;
}
@@ -1421,6 +1422,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
char cid_buf[1024] = "";
if (switch_channel_ready(channel)) {
+ const char *vm_announce_cid = NULL;
switch_snprintf(cid_buf, sizeof(cid_buf), "%s|%s", cbt->cid_number, cbt->cid_name);
@@ -1428,7 +1430,13 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
msg.string_arg = cid_buf;
msg.message_id = SWITCH_MESSAGE_INDICATE_DISPLAY;
switch_core_session_receive_message(session, &msg);
-
+
+ if (!zstr(cbt->cid_number) && (vm_announce_cid = switch_channel_get_variable(channel, "vm_announce_cid"))) {
+ switch_ivr_play_file(session, NULL, vm_announce_cid, NULL);
+ switch_ivr_sleep(session, 500, SWITCH_TRUE, NULL);
+ switch_ivr_say(session, cbt->cid_number, NULL, "name_spelled", "pronounced", NULL, NULL);
+ }
+
args.input_callback = cancel_on_dtmf;
switch_snprintf(key_buf, sizeof(key_buf), "%s:%s:%s:%s:%s:%s%s%s", profile->listen_file_key, profile->save_file_key,
@@ -1523,7 +1531,7 @@ static switch_status_t listen_file(switch_core_session_t *session, vm_profile_t
vm_cc[0] = '\0';
TRY_CODE(switch_ivr_read
- (session, 0, sizeof(vm_cc), macro_buf, NULL, vm_cc, sizeof(vm_cc), profile->digit_timeout, profile->terminator_key));
+ (session, 0, sizeof(vm_cc), macro_buf, NULL, vm_cc, sizeof(vm_cc), profile->digit_timeout, profile->terminator_key, 0));
cmd = switch_core_session_sprintf(session, "%s@%s %s %s '%s'", vm_cc, cbt->domain, new_file_path, cbt->cid_number, cbt->cid_name);
@@ -1987,7 +1995,7 @@ static void voicemail_check_main(switch_core_session_t *session, vm_profile_t *p
switch_xml_t xx_user, xx_domain, xx_domain_root;
switch_snprintf(macro, sizeof(macro), "phrase:%s:%s", VM_ENTER_PASS_MACRO, profile->terminator_key);
- TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key));
+ TRY_CODE(switch_ivr_read(session, 0, 255, macro, NULL, buf, sizeof(buf), 10000, profile->terminator_key, 0));
sql = switch_mprintf("update voicemail_prefs set password='%s' where username='%s' and domain='%s'", buf, myid, domain_name);
vm_execute_sql(profile, sql, profile->mutex);
switch_safe_free(file_path);
@@ -2686,23 +2694,29 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
if ((domain = strchr(user, '@'))) {
*domain++ = '\0';
- } else {
- domain = user;
- }
- if ((profile_name = strchr(domain, '@'))) {
- *profile_name++ = '\0';
- } else {
- profile_name = domain;
+ if ((profile_name = strchr(domain, '@'))) {
+ *profile_name++ = '\0';
+ } else {
+ profile_name = domain;
+ }
}
if (switch_stristr("group=", user)) {
user += 6;
isgroup++;
- } else if (user == domain) {
+ } else if (switch_stristr("domain=", user)) {
+ user += 7;
+ domain = user;
+ profile_name = domain;
isall++;
}
+ if (zstr(domain)) {
+ domain = switch_core_get_variable("domain");
+ profile_name = domain;
+ }
+
if (!(user && domain)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid syntax [%s][%s]\n", switch_str_nil(user), switch_str_nil(domain));
status = SWITCH_STATUS_FALSE;
@@ -2746,6 +2760,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate domain %s\n", domain);
status = SWITCH_STATUS_FALSE;
switch_event_destroy(&my_params);
+ profile_rwunlock(profile);
goto end;
}
@@ -3164,7 +3179,7 @@ static switch_status_t voicemail_leave_main(switch_core_session_t *session, vm_p
switch_event_destroy(&vars);
if (status == SWITCH_STATUS_SUCCESS) {
if ((vm_cc = switch_channel_get_variable(channel, "vm_cc"))) {
- char *cmd = switch_core_session_sprintf(session, "%s %s %s %s %s@%s %s",
+ char *cmd = switch_core_session_sprintf(session, "%s %s %s '%s' %s@%s %s",
vm_cc, file_path, caller_id_number, caller_id_name, id, domain_name, read_flags);
if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) {
@@ -3670,7 +3685,7 @@ static int web_callback(void *pArg, int argc, char **argv, char **columnNames)
const char *fmt = "%a, %e %b %Y %T %z";
char heard[80];
char title_b4[128] = "";
- char title_aft[128 * 3] = "";
+ char title_aft[128 * 3 + 1] = "";
if (argc > 0) {
l_created = switch_time_make(atol(argv[0]), 0);
@@ -3961,7 +3976,7 @@ static void do_web(vm_profile_t *profile, const char *user_in, const char *domai
}
}
-#define VM_INJECT_USAGE "[group=] [] []"
+#define VM_INJECT_USAGE "[group=[@domain]|domain=|[@]] [] []"
SWITCH_STANDARD_API(voicemail_inject_api_function)
{
if (voicemail_inject(cmd, session) == SWITCH_STATUS_SUCCESS) {
diff --git a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
index 139fe217a3..4b36e1435e 100644
--- a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
+++ b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c
@@ -2724,7 +2724,7 @@ static switch_status_t recog_asr_open(switch_asr_handle_t *ah, const char *codec
name++;
name = switch_core_sprintf(ah->memory_pool, "%s ASR-%d", name, speech_channel_number);
} else {
- name = switch_core_sprintf(ah->memory_pool, "ASR-%d", name, speech_channel_number);
+ name = switch_core_sprintf(ah->memory_pool, "ASR-%d", speech_channel_number);
}
/* Allocate the channel */
diff --git a/src/mod/codecs/mod_amr/mod_amr.c b/src/mod/codecs/mod_amr/mod_amr.c
index a864254e28..e8925c4581 100644
--- a/src/mod/codecs/mod_amr/mod_amr.c
+++ b/src/mod/codecs/mod_amr/mod_amr.c
@@ -98,11 +98,8 @@ typedef enum {
AMR_DTX_ENABLED
} amr_dtx_t;
-struct amr_context {
- void *encoder_state;
- void *decoder_state;
- switch_byte_t enc_modes;
- switch_byte_t enc_mode;
+/*! \brief Various codec settings */
+struct amr_codec_settings {
int dtx_mode;
uint32_t change_period;
switch_byte_t max_ptime;
@@ -110,6 +107,24 @@ struct amr_context {
switch_byte_t channels;
switch_byte_t flags;
};
+typedef struct amr_codec_settings amr_codec_settings_t;
+
+static amr_codec_settings_t default_codec_settings = {
+ /*.dtx_mode */ AMR_DTX_ENABLED,
+ /*.change_period */ 0,
+ /*.max_ptime */ 0,
+ /*.ptime */ 0,
+ /*.channels */ 0,
+ /*.flags */ 0,
+};
+
+
+struct amr_context {
+ void *encoder_state;
+ void *decoder_state;
+ switch_byte_t enc_modes;
+ switch_byte_t enc_mode;
+};
#define AMR_DEFAULT_BITRATE AMR_BITRATE_1220
@@ -117,6 +132,88 @@ static struct {
switch_byte_t default_bitrate;
} globals;
+static switch_status_t switch_amr_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+ if (codec_fmtp) {
+ amr_codec_settings_t *codec_settings = NULL;
+ if (codec_fmtp->private_info) {
+ codec_settings = codec_fmtp->private_info;
+ memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+ }
+
+ if (fmtp) {
+ int x, argc;
+ char *argv[10];
+ char *fmtp_dup = strdup(fmtp);
+
+ switch_assert(fmtp_dup);
+
+ argc = switch_separate_string((char *) fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+ for (x = 0; x < argc; x++) {
+ char *data = argv[x];
+ char *arg;
+ switch_assert(data);
+ while (*data == ' ') {
+ data++;
+ }
+ if ((arg = strchr(data, '='))) {
+ *arg++ = '\0';
+ /*
+ if (!strcasecmp(data, "bitrate")) {
+ bit_rate = atoi(arg);
+ }
+ */
+ if (codec_settings) {
+ if (!strcasecmp(data, "octet-align")) {
+ if (atoi(arg)) {
+ switch_set_flag(codec_settings, AMR_OPT_OCTET_ALIGN);
+ }
+ } else if (!strcasecmp(data, "mode-change-neighbor")) {
+ if (atoi(arg)) {
+ switch_set_flag(codec_settings, AMR_OPT_MODE_CHANGE_NEIGHBOR);
+ }
+ } else if (!strcasecmp(data, "crc")) {
+ if (atoi(arg)) {
+ switch_set_flag(codec_settings, AMR_OPT_CRC);
+ }
+ } else if (!strcasecmp(data, "robust-sorting")) {
+ if (atoi(arg)) {
+ switch_set_flag(codec_settings, AMR_OPT_ROBUST_SORTING);
+ }
+ } else if (!strcasecmp(data, "interveaving")) {
+ if (atoi(arg)) {
+ switch_set_flag(codec_settings, AMR_OPT_INTERLEAVING);
+ }
+ } else if (!strcasecmp(data, "mode-change-period")) {
+ codec_settings->change_period = atoi(arg);
+ } else if (!strcasecmp(data, "ptime")) {
+ codec_settings->ptime = (switch_byte_t) atoi(arg);
+ } else if (!strcasecmp(data, "channels")) {
+ codec_settings->channels = (switch_byte_t) atoi(arg);
+ } else if (!strcasecmp(data, "maxptime")) {
+ codec_settings->max_ptime = (switch_byte_t) atoi(arg);
+ } else if (!strcasecmp(data, "mode-set")) {
+ int y, m_argc;
+ char *m_argv[7];
+ m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0])));
+ for (y = 0; y < m_argc; y++) {
+ codec_settings->enc_modes |= (1 << atoi(m_argv[y]));
+ }
+ } else if (!strcasecmp(data, "dtx")) {
+ codec_settings->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED;
+ }
+ }
+
+ }
+ }
+ free(fmtp_dup);
+ }
+ //codec_fmtp->bits_per_second = bit_rate;
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
#endif
static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
@@ -128,7 +225,10 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_
}
return SWITCH_STATUS_SUCCESS;
#else
+
struct amr_context *context = NULL;
+ switch_codec_fmtp_t codec_fmtp;
+ amr_codec_settings_t amr_codec_settings;
int encoding, decoding;
int x, i, argc;
char *argv[10];
@@ -141,58 +241,9 @@ static switch_status_t switch_amr_init(switch_codec_t *codec, switch_codec_flag_
return SWITCH_STATUS_FALSE;
} else {
- context->dtx_mode = AMR_DTX_ENABLED;
- if (codec->fmtp_in) {
- argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- while (*data && *data == ' ') {
- data++;
- }
- if ((arg = strchr(data, '='))) {
- *arg++ = '\0';
- if (!strcasecmp(data, "octet-align")) {
- if (atoi(arg)) {
- switch_set_flag(context, AMR_OPT_OCTET_ALIGN);
- }
- } else if (!strcasecmp(data, "mode-change-neighbor")) {
- if (atoi(arg)) {
- switch_set_flag(context, AMR_OPT_MODE_CHANGE_NEIGHBOR);
- }
- } else if (!strcasecmp(data, "crc")) {
- if (atoi(arg)) {
- switch_set_flag(context, AMR_OPT_CRC);
- }
- } else if (!strcasecmp(data, "robust-sorting")) {
- if (atoi(arg)) {
- switch_set_flag(context, AMR_OPT_ROBUST_SORTING);
- }
- } else if (!strcasecmp(data, "interveaving")) {
- if (atoi(arg)) {
- switch_set_flag(context, AMR_OPT_INTERLEAVING);
- }
- } else if (!strcasecmp(data, "mode-change-period")) {
- context->change_period = atoi(arg);
- } else if (!strcasecmp(data, "ptime")) {
- context->ptime = (switch_byte_t) atoi(arg);
- } else if (!strcasecmp(data, "channels")) {
- context->channels = (switch_byte_t) atoi(arg);
- } else if (!strcasecmp(data, "maxptime")) {
- context->max_ptime = (switch_byte_t) atoi(arg);
- } else if (!strcasecmp(data, "mode-set")) {
- int y, m_argc;
- char *m_argv[7];
- m_argc = switch_separate_string(arg, ',', m_argv, (sizeof(m_argv) / sizeof(m_argv[0])));
- for (y = 0; y < m_argc; y++) {
- context->enc_modes |= (1 << atoi(m_argv[y]));
- }
- } else if (!strcasecmp(data, "dtx")) {
- context->dtx_mode = (atoi(arg)) ? AMR_DTX_ENABLED : AMR_DTX_DISABLED;
- }
- }
- }
- }
+ memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+ codec_fmtp.private_info = &amr_codec_settings;
+ switch_amr_fmtp_parse(codec->fmtp_in, &codec_fmtp);
if (context->enc_modes) {
for (i = 7; i > -1; i++) {
@@ -321,6 +372,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_amr_load)
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "AMR");
+#ifndef AMR_PASSTHROUGH
+ codec_interface->parse_fmtp = switch_amr_fmtp_parse;
+#endif
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
96, /* the IANA code number */
"AMR", /* the IANA code name */
diff --git a/src/mod/codecs/mod_codec2/Makefile b/src/mod/codecs/mod_codec2/Makefile
new file mode 100644
index 0000000000..568df9c64d
--- /dev/null
+++ b/src/mod/codecs/mod_codec2/Makefile
@@ -0,0 +1,14 @@
+BASE=../../../..
+
+CODEC2_DIR=$(switch_srcdir)/libs/libcodec2
+CODEC2_BUILDDIR=$(switch_builddir)/libs/libcodec2
+CODEC2LA=$(CODEC2_BUILDDIR)/src/libcodec2.la
+
+LOCAL_CFLAGS=-I$(CODEC2_DIR)/include -I$(CODEC2_BUILDDIR)/src
+LOCAL_LIBADD=$(CODEC2LA)
+include $(BASE)/build/modmake.rules
+
+$(CODEC2LA): $(CODEC2_DIR) $(CODEC2_DIR)/.update
+ cd $(CODEC2_BUILDDIR) && $(MAKE)
+ $(TOUCH_TARGET)
+
diff --git a/src/mod/codecs/mod_codec2/mod_codec2.c b/src/mod/codecs/mod_codec2/mod_codec2.c
new file mode 100644
index 0000000000..e7aa645090
--- /dev/null
+++ b/src/mod/codecs/mod_codec2/mod_codec2.c
@@ -0,0 +1,264 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library
+ *
+ * The Initial Developer of the Original Code is
+ * Brian West
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mathieu Rene
+ *
+ * mod_codec2 -- FreeSWITCH CODEC2 Module
+ *
+ */
+
+#include
+#include
+
+/* Uncomment to log input/output data for debugging
+#define LOG_DATA
+#define CODEC2_DEBUG
+*/
+
+#ifdef CODEC2_DEBUG
+#define codec2_assert(_x) switch_assert(_x)
+#else
+#define codec2_assert(_x)
+#endif
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load);
+
+SWITCH_MODULE_DEFINITION(mod_codec2, mod_codec2_load, NULL, NULL);
+
+struct codec2_context {
+ void *encoder;
+ void *decoder;
+#ifdef LOG_DATA
+ FILE *encoder_in;
+ FILE *encoder_out;
+ FILE *encoder_out_unpacked;
+ FILE *decoder_in;
+ FILE *decoder_in_unpacked;
+ FILE *decoder_out;
+#endif
+};
+
+#ifdef LOG_DATA
+static int c2_count = 0;
+#endif
+
+static switch_status_t switch_codec2_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
+{
+ uint32_t encoding, decoding;
+ struct codec2_context *context = NULL;
+
+ encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+ decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+ if (!(encoding || decoding)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context)))) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (encoding) {
+ context->encoder = codec2_create();
+ }
+
+ if (decoding) {
+ context->decoder = codec2_create();
+ }
+
+ codec->private_info = context;
+
+#ifdef LOG_DATA
+ {
+
+ int c = c2_count++;
+ char buf[1024];
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Logging as /tmp/c2-%d-*\n", c);
+
+ if (encoding) {
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-in", c);
+ context->encoder_in = fopen(buf, "w");
+
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-out", c);
+ context->encoder_out = fopen(buf, "w");
+
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-enc-out-unpacked", c);
+ context->encoder_out_unpacked = fopen(buf, "w");
+ }
+ if (decoding) {
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-in", c);
+ context->decoder_in = fopen(buf, "w");
+
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-out", c);
+ context->decoder_out = fopen(buf, "w");
+
+ snprintf(buf, sizeof(buf), "/tmp/c2-%d-dec-out-unpacked", c);
+ context->decoder_in_unpacked = fopen(buf, "w");
+ }
+ }
+#endif
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_encode(switch_codec_t *codec, switch_codec_t *other_codec,
+ void *decoded_data,
+ uint32_t decoded_data_len,
+ uint32_t decoded_rate,
+ void *encoded_data,
+ uint32_t *encoded_data_len,
+ uint32_t *encoded_rate,
+ unsigned int *flag)
+{
+ struct codec2_context *context = codec->private_info;
+
+ codec2_assert(decoded_data_len == CODEC2_SAMPLES_PER_FRAME * 2);
+
+#ifdef LOG_DATA
+ fwrite(decoded_data, decoded_data_len, 1, context->encoder_in);
+ fflush(context->encoder_in);
+#endif
+
+ codec2_encode(context->encoder, encoded_data, decoded_data);
+
+#ifdef LOG_DATA
+ fwrite(encode_buf, sizeof(encode_buf), 1, context->encoder_out_unpacked);
+ fflush(context->encoder_out_unpacked);
+ fwrite(encoded_data, 8, 1, context->encoder_out);
+ fflush(context->encoder_out);
+#endif
+
+ *encoded_data_len = 8;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_decode(switch_codec_t *codec,
+ switch_codec_t *other_codec,
+ void *encoded_data,
+ uint32_t encoded_data_len,
+ uint32_t encoded_rate,
+ void *decoded_data,
+ uint32_t *decoded_data_len,
+ uint32_t *decoded_rate,
+ unsigned int *flag)
+{
+ struct codec2_context *context = codec->private_info;
+
+ codec2_assert(encoded_data_len == 8 /* aligned to 8 */);
+
+#ifdef LOG_DATA
+ fwrite(encoded_data, encoded_data_len, 1, context->decoder_in);
+ fflush(context->decoder_in);
+ fwrite(bits, sizeof(bits), 1, context->decoder_in_unpacked);
+ fflush(context->decoder_in_unpacked);
+#endif
+
+ codec2_decode(context->decoder, decoded_data, encoded_data);
+
+#ifdef LOG_DATA
+ fwrite(decoded_data, CODEC2_SAMPLES_PER_FRAME, 2, context->decoder_out);
+ fflush(context->decoder_out);
+#endif
+
+ *decoded_data_len = CODEC2_SAMPLES_PER_FRAME * 2; /* 160 samples */
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_codec2_destroy(switch_codec_t *codec)
+{
+ struct codec2_context *context = codec->private_info;
+
+ codec2_destroy(context->encoder);
+ codec2_destroy(context->decoder);
+
+ context->encoder = NULL;
+ context->decoder = NULL;
+
+#ifdef LOG_DATA
+ if (context->encoder_in) {
+ fclose(context->encoder_in);
+ }
+ if (context->encoder_out) {
+ fclose(context->encoder_out);
+ }
+ if (context->encoder_out_unpacked) {
+ fclose(context->encoder_out_unpacked);
+ }
+ if (context->decoder_in) {
+ fclose(context->decoder_in);
+ }
+ if (context->decoder_in_unpacked) {
+ fclose(context->decoder_in_unpacked);
+ }
+ if (context->decoder_out) {
+ fclose(context->decoder_out);
+ }
+#endif
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_codec2_load)
+{
+ switch_codec_interface_t *codec_interface;
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ SWITCH_ADD_CODEC(codec_interface, "CODEC2 2550bps");
+
+ switch_core_codec_add_implementation(pool, codec_interface,
+ SWITCH_CODEC_TYPE_AUDIO,
+ 111,
+ "CODEC2",
+ NULL,
+ 8000, /* samples/sec */
+ 8000, /* samples/sec */
+ 2550, /* bps */
+ 20000, /* ptime */
+ CODEC2_SAMPLES_PER_FRAME, /* samples decoded */
+ CODEC2_SAMPLES_PER_FRAME*2, /* bytes decoded */
+ 0, /* bytes encoded */
+ 1, /* channels */
+ 1, /* frames/packet */
+ switch_codec2_init,
+ switch_codec2_encode,
+ switch_codec2_decode,
+ switch_codec2_destroy);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* 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:
+ */
diff --git a/src/mod/codecs/mod_ilbc/mod_ilbc.c b/src/mod/codecs/mod_ilbc/mod_ilbc.c
index b37056c393..85298375db 100644
--- a/src/mod/codecs/mod_ilbc/mod_ilbc.c
+++ b/src/mod/codecs/mod_ilbc/mod_ilbc.c
@@ -40,6 +40,27 @@ struct ilbc_context {
ilbc_decode_state_t decoder_object;
};
+static switch_status_t switch_ilbc_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+ if (codec_fmtp) {
+ char *mode = NULL;
+ int codec_ms = 0;
+
+ memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+
+ if (fmtp && (mode = strstr(fmtp, "mode=")) && (mode + 5)) {
+ codec_ms = atoi(mode + 5);
+ }
+ if (!codec_ms) {
+ /* default to 30 when no mode is defined for ilbc ONLY */
+ codec_ms = 30;
+ }
+ codec_fmtp->microseconds_per_packet = (codec_ms * 1000);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
struct ilbc_context *context;
@@ -51,26 +72,6 @@ static switch_status_t switch_ilbc_init(switch_codec_t *codec, switch_codec_flag
return SWITCH_STATUS_FALSE;
}
- if (codec->fmtp_in) {
- int x, argc;
- char *argv[10];
- argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- switch_assert(data);
- while (*data == ' ') {
- data++;
- }
- if ((arg = strchr(data, '='))) {
- *arg++ = '\0';
- if (!strcasecmp(data, "mode")) {
- mode = atoi(arg);
- }
- }
- }
- }
-
codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "mode=%d", mode);
if (encoding) {
@@ -136,6 +137,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_ilbc_load)
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "iLBC");
+ codec_interface->parse_fmtp = switch_ilbc_fmtp_parse;
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
98, /* the IANA code number */
diff --git a/src/mod/codecs/mod_silk/mod_silk.c b/src/mod/codecs/mod_silk/mod_silk.c
index 9d0abcdf8b..934c9ebe32 100644
--- a/src/mod/codecs/mod_silk/mod_silk.c
+++ b/src/mod/codecs/mod_silk/mod_silk.c
@@ -41,6 +41,22 @@ SWITCH_MODULE_DEFINITION(mod_silk, mod_silk_load, NULL, NULL);
#define MAX_LBRR_DELAY 2
#define MAX_FRAME_LENGTH 480
+/*! \brief Various codec settings */
+struct silk_codec_settings {
+ SKP_int useinbandfec;
+ SKP_int usedtx;
+ SKP_int maxaveragebitrate;
+ SKP_int plpct;
+};
+typedef struct silk_codec_settings silk_codec_settings_t;
+
+static silk_codec_settings_t default_codec_settings = {
+ /*.useinbandfec */ 0,
+ /*.usedtx */ 0,
+ /*.maxaveragebitrate */ 0,
+ /*.plpct */ 10, // 10% for now
+};
+
struct silk_context {
SKP_SILK_SDK_EncControlStruct encoder_object;
SKP_SILK_SDK_DecControlStruct decoder_object;
@@ -48,12 +64,105 @@ struct silk_context {
void *dec_state;
};
+static switch_status_t switch_silk_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+ if (codec_fmtp) {
+ silk_codec_settings_t *codec_settings = NULL;
+
+ if (codec_fmtp->private_info) {
+ codec_settings = codec_fmtp->private_info;
+ memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+ }
+
+ if (fmtp) {
+ int x, argc;
+ char *argv[10];
+ char *fmtp_dup = strdup(fmtp);
+
+ switch_assert(fmtp_dup);
+
+ argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+ for (x = 0; x < argc; x++) {
+ char *data = argv[x];
+ char *arg;
+ switch_assert(data);
+ while (*data == ' ') {
+ data++;
+ }
+ if ((arg = strchr(data, '='))) {
+ *arg++ = '\0';
+ if (codec_settings) {
+ if (!strcasecmp(data, "useinbandfec")) {
+ if (switch_true(arg)) {
+ codec_settings->useinbandfec = 1;
+ }
+ }
+ if (!strcasecmp(data, "usedtx")) {
+ if (switch_true(arg)) {
+ codec_settings->usedtx = 1;
+ }
+ }
+ if (!strcasecmp(data, "maxaveragebitrate")) {
+ codec_settings->maxaveragebitrate = atoi(arg);
+ switch(codec_fmtp->actual_samples_per_second) {
+ case 8000:
+ {
+ if(codec_settings->maxaveragebitrate < 6000 || codec_settings->maxaveragebitrate > 20000) {
+ codec_settings->maxaveragebitrate = 20000;
+ }
+ break;
+ }
+ case 12000:
+ {
+ if(codec_settings->maxaveragebitrate < 7000 || codec_settings->maxaveragebitrate > 25000) {
+ codec_settings->maxaveragebitrate = 25000;
+ }
+ break;
+ }
+ case 16000:
+ {
+ if(codec_settings->maxaveragebitrate < 8000 || codec_settings->maxaveragebitrate > 30000) {
+ codec_settings->maxaveragebitrate = 30000;
+ }
+ break;
+ }
+ case 24000:
+ {
+ if(codec_settings->maxaveragebitrate < 12000 || codec_settings->maxaveragebitrate > 40000) {
+ codec_settings->maxaveragebitrate = 40000;
+ }
+ break;
+ }
+
+ default:
+ /* this should never happen but 20000 is common among all rates */
+ codec_settings->maxaveragebitrate = 20000;
+ break;
+ }
+
+ }
+
+ }
+ }
+ }
+ free(fmtp_dup);
+ }
+ //codec_fmtp->bits_per_second = bit_rate;
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+
+
+
static switch_status_t switch_silk_init(switch_codec_t *codec,
switch_codec_flag_t freeswitch_flags,
const switch_codec_settings_t *codec_settings)
{
struct silk_context *context = NULL;
- SKP_int useinbandfec = 0, usedtx = 0, maxaveragebitrate = 0, plpct =0;
+ switch_codec_fmtp_t codec_fmtp;
+ silk_codec_settings_t silk_codec_settings;
SKP_int32 encSizeBytes;
SKP_int32 decSizeBytes;
int encoding = (freeswitch_flags & SWITCH_CODEC_FLAG_ENCODE);
@@ -62,78 +171,15 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
return SWITCH_STATUS_FALSE;
}
-
- if (codec->fmtp_in) {
- int x, argc;
- char *argv[10];
- argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- switch_assert(data);
- while (*data == ' ') {
- data++;
- }
- if ((arg = strchr(data, '='))) {
- *arg++ = '\0';
- if (!strcasecmp(data, "useinbandfec")) {
- if (switch_true(arg)) {
- useinbandfec = 1;
- plpct = 10;// 10% for now
- }
- }
- if (!strcasecmp(data, "usedtx")) {
- if (switch_true(arg)) {
- usedtx = 1;
- }
- }
- if (!strcasecmp(data, "maxaveragebitrate")) {
- maxaveragebitrate = atoi(arg);
- switch(codec->implementation->actual_samples_per_second) {
- case 8000:
- {
- if(maxaveragebitrate < 6000 || maxaveragebitrate > 20000) {
- maxaveragebitrate = 20000;
- }
- break;
- }
- case 12000:
- {
- if(maxaveragebitrate < 7000 || maxaveragebitrate > 25000) {
- maxaveragebitrate = 25000;
- }
- break;
- }
- case 16000:
- {
- if(maxaveragebitrate < 8000 || maxaveragebitrate > 30000) {
- maxaveragebitrate = 30000;
- }
- break;
- }
- case 24000:
- {
- if(maxaveragebitrate < 12000 || maxaveragebitrate > 40000) {
- maxaveragebitrate = 40000;
- }
- break;
- }
-
- default:
- /* this should never happen but 20000 is common among all rates */
- maxaveragebitrate = 20000;
- break;
- }
-
- }
- }
- }
- }
+
+ memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+ codec_fmtp.private_info = &silk_codec_settings;
+ switch_silk_fmtp_parse(codec->fmtp_in, &codec_fmtp);
codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "useinbandfec=%s; usedtx=%s; maxaveragebitrate=%d",
- useinbandfec ? "1" : "0",
- usedtx ? "1" : "0",
- maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second);
+ silk_codec_settings.useinbandfec ? "1" : "0",
+ silk_codec_settings.usedtx ? "1" : "0",
+ silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second);
if (encoding) {
if (SKP_Silk_SDK_Get_Encoder_Size(&encSizeBytes)) {
@@ -148,11 +194,11 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
context->encoder_object.sampleRate = codec->implementation->actual_samples_per_second;
context->encoder_object.packetSize = codec->implementation->samples_per_packet;
- context->encoder_object.useInBandFEC = useinbandfec;
+ context->encoder_object.useInBandFEC = silk_codec_settings.useinbandfec;
context->encoder_object.complexity = 0;
- context->encoder_object.bitRate = maxaveragebitrate ? maxaveragebitrate : codec->implementation->bits_per_second;
- context->encoder_object.useDTX = usedtx;
- context->encoder_object.packetLossPercentage = plpct;;
+ context->encoder_object.bitRate = silk_codec_settings.maxaveragebitrate ? silk_codec_settings.maxaveragebitrate : codec->implementation->bits_per_second;
+ context->encoder_object.useDTX = silk_codec_settings.usedtx;
+ context->encoder_object.packetLossPercentage = silk_codec_settings.plpct;
}
if (decoding) {
@@ -174,7 +220,7 @@ static switch_status_t switch_silk_init(switch_codec_t *codec,
static switch_status_t switch_silk_destroy(switch_codec_t *codec)
{
- codec->private_info = NULL;
+ codec->private_info = NULL;
return SWITCH_STATUS_SUCCESS;
}
@@ -299,6 +345,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_silk_load)
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "SILK");
+ codec_interface->parse_fmtp = switch_silk_fmtp_parse;
switch_core_codec_add_implementation(pool, codec_interface,
SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
117, /* the IANA code number */
diff --git a/src/mod/codecs/mod_siren/mod_siren.c b/src/mod/codecs/mod_siren/mod_siren.c
index 1ccd36eafb..4646ffc5ae 100644
--- a/src/mod/codecs/mod_siren/mod_siren.c
+++ b/src/mod/codecs/mod_siren/mod_siren.c
@@ -47,6 +47,40 @@ struct siren_context {
g722_1_encode_state_t encoder_object;
};
+static switch_status_t switch_siren_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+ if (codec_fmtp) {
+ int bit_rate = 0;
+ memset(codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+ if (fmtp) {
+ int x, argc;
+ char *argv[10];
+ char *fmtp_dup = strdup(fmtp);
+
+ switch_assert(fmtp_dup);
+ argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+ for (x = 0; x < argc; x++) {
+ char *data = argv[x];
+ char *arg;
+ switch_assert(data);
+ while (*data == ' ') {
+ data++;
+ }
+ if ((arg = strchr(data, '='))) {
+ *arg++ = '\0';
+ if (!strcasecmp(data, "bitrate")) {
+ bit_rate = atoi(arg);
+ }
+ }
+ }
+ free(fmtp_dup);
+ }
+ codec_fmtp->bits_per_second = bit_rate;
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
struct siren_context *context = NULL;
@@ -58,26 +92,6 @@ static switch_status_t switch_siren_init(switch_codec_t *codec, switch_codec_fla
return SWITCH_STATUS_FALSE;
}
- if (codec->fmtp_in) {
- int x, argc;
- char *argv[10];
- argc = switch_separate_string(codec->fmtp_in, ';', argv, (sizeof(argv) / sizeof(argv[0])));
- for (x = 0; x < argc; x++) {
- char *data = argv[x];
- char *arg;
- switch_assert(data);
- while (*data == ' ') {
- data++;
- }
- if ((arg = strchr(data, '='))) {
- *arg++ = '\0';
- if (!strcasecmp(data, "bitrate")) {
- bit_rate = atoi(arg);
- }
- }
- }
- }
-
codec->fmtp_out = switch_core_sprintf(codec->memory_pool, "bitrate=%d", bit_rate);
if (encoding) {
@@ -145,6 +159,28 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_siren_load)
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "Polycom(R) G722.1/G722.1C");
+ codec_interface->parse_fmtp = switch_siren_fmtp_parse;
+
+ spf = 320, bpf = 640;
+ for (count = 3; count > 0; count--) {
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 107, /* the IANA code number */
+ "G7221", /* the IANA code name */
+ "bitrate=24000", /* default fmtp to send (can be overridden by the init function) */
+ 16000, /* samples transferred per second */
+ 16000, /* actual samples transferred per second */
+ 24000, /* bits transferred per second */
+ mpf * count, /* number of microseconds per frame */
+ spf * count, /* number of samples per frame */
+ bpf * count, /* number of bytes per frame decompressed */
+ 0, /* number of bytes per frame compressed */
+ 1, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_siren_init, /* function to initialize a codec handle using this implementation */
+ switch_siren_encode, /* function to encode raw data into encoded data */
+ switch_siren_decode, /* function to decode encoded data into raw data */
+ switch_siren_destroy); /* deinitalize a codec handle using this implementation */
+ }
spf = 320, bpf = 640;
for (count = 3; count > 0; count--) {
diff --git a/src/mod/codecs/mod_speex/mod_speex.c b/src/mod/codecs/mod_speex/mod_speex.c
index 1d4a0409b8..a951b12d84 100644
--- a/src/mod/codecs/mod_speex/mod_speex.c
+++ b/src/mod/codecs/mod_speex/mod_speex.c
@@ -37,7 +37,46 @@
SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load);
SWITCH_MODULE_DEFINITION(mod_speex, mod_speex_load, NULL, NULL);
-static switch_codec_settings_t default_codec_settings = {
+/* nobody has more setting than speex so we will let them set the standard */
+/*! \brief Various codec settings (currently only relevant to speex) */
+struct speex_codec_settings {
+ /*! desired quality */
+ int quality;
+ /*! desired complexity */
+ int complexity;
+ /*! desired enhancement */
+ int enhancement;
+ /*! desired vad level */
+ int vad;
+ /*! desired vbr level */
+ int vbr;
+ /*! desired vbr quality */
+ float vbr_quality;
+ /*! desired abr level */
+ int abr;
+ /*! desired dtx setting */
+ int dtx;
+ /*! desired preprocessor settings */
+ int preproc;
+ /*! preprocessor vad settings */
+ int pp_vad;
+ /*! preprocessor gain control settings */
+ int pp_agc;
+ /*! preprocessor gain level */
+ float pp_agc_level;
+ /*! preprocessor denoise level */
+ int pp_denoise;
+ /*! preprocessor dereverb settings */
+ int pp_dereverb;
+ /*! preprocessor dereverb decay level */
+ float pp_dereverb_decay;
+ /*! preprocessor dereverb level */
+ float pp_dereverb_level;
+};
+
+typedef struct speex_codec_settings speex_codec_settings_t;
+
+static speex_codec_settings_t default_codec_settings = {
/*.quality */ 5,
/*.complexity */ 5,
/*.enhancement */ 1,
@@ -58,6 +97,7 @@ static switch_codec_settings_t default_codec_settings = {
struct speex_context {
switch_codec_t *codec;
+ speex_codec_settings_t codec_settings;
unsigned int flags;
/* Encoder */
@@ -74,6 +114,56 @@ struct speex_context {
int decoder_mode;
};
+static switch_status_t switch_speex_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
+{
+ if (codec_fmtp) {
+ speex_codec_settings_t *codec_settings = NULL;
+ if (codec_fmtp->private_info) {
+ codec_settings = codec_fmtp->private_info;
+ memcpy(codec_settings, &default_codec_settings, sizeof(*codec_settings));
+ }
+
+ if (fmtp) {
+ int x, argc;
+ char *argv[10];
+ char *fmtp_dup = strdup(fmtp);
+
+ switch_assert(fmtp_dup);
+
+ argc = switch_separate_string(fmtp_dup, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ for (x = 0; x < argc; x++) {
+ char *data = argv[x];
+ char *arg;
+ switch_assert(data);
+ while (*data == ' ') {
+ data++;
+ }
+ if ((arg = strchr(data, '='))) {
+ *arg++ = '\0';
+ /*
+ if (!strcasecmp(data, "bitrate")) {
+ bit_rate = atoi(arg);
+ }
+ */
+ /*
+ if (codec_settings) {
+ if (!strcasecmp(data, "vad")) {
+ bit_rate = atoi(arg);
+ }
+ }
+ */
+ }
+ }
+ free(fmtp_dup);
+ }
+ /*codec_fmtp->bits_per_second = bit_rate;*/
+ return SWITCH_STATUS_SUCCESS;
+ }
+ return SWITCH_STATUS_FALSE;
+}
+
+
static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
struct speex_context *context = NULL;
@@ -82,16 +172,18 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla
encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
- if (!codec_settings) {
- codec_settings = &default_codec_settings;
- }
-
- memcpy(&codec->codec_settings, codec_settings, sizeof(codec->codec_settings));
-
if (!(encoding || decoding) || ((context = switch_core_alloc(codec->memory_pool, sizeof(*context))) == 0)) {
return SWITCH_STATUS_FALSE;
} else {
const SpeexMode *mode = NULL;
+ switch_codec_fmtp_t codec_fmtp;
+ speex_codec_settings_t codec_settings;
+
+ memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
+ codec_fmtp.private_info = &codec_settings;
+ switch_speex_fmtp_parse(codec->fmtp_in, &codec_fmtp);
+
+ memcpy(&context->codec_settings, &codec_settings, sizeof(context->codec_settings));
context->codec = codec;
if (codec->implementation->actual_samples_per_second == 8000) {
@@ -110,41 +202,41 @@ static switch_status_t switch_speex_init(switch_codec_t *codec, switch_codec_fla
speex_bits_init(&context->encoder_bits);
context->encoder_state = speex_encoder_init(mode);
speex_encoder_ctl(context->encoder_state, SPEEX_GET_FRAME_SIZE, &context->encoder_frame_size);
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &codec->codec_settings.complexity);
- if (codec->codec_settings.preproc) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &context->codec_settings.complexity);
+ if (context->codec_settings.preproc) {
context->pp = speex_preprocess_state_init(context->encoder_frame_size, codec->implementation->actual_samples_per_second);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &codec->codec_settings.pp_vad);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &codec->codec_settings.pp_agc);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &codec->codec_settings.pp_agc_level);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &codec->codec_settings.pp_denoise);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &codec->codec_settings.pp_dereverb);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &codec->codec_settings.pp_dereverb_decay);
- speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &codec->codec_settings.pp_dereverb_level);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &context->codec_settings.pp_vad);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &context->codec_settings.pp_agc);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &context->codec_settings.pp_agc_level);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &context->codec_settings.pp_denoise);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &context->codec_settings.pp_dereverb);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &context->codec_settings.pp_dereverb_decay);
+ speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &context->codec_settings.pp_dereverb_level);
}
- if (!codec->codec_settings.abr && !codec->codec_settings.vbr) {
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &codec->codec_settings.quality);
- if (codec->codec_settings.vad) {
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &codec->codec_settings.vad);
+ if (!context->codec_settings.abr && !context->codec_settings.vbr) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &context->codec_settings.quality);
+ if (context->codec_settings.vad) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &context->codec_settings.vad);
}
}
- if (codec->codec_settings.vbr) {
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &codec->codec_settings.vbr);
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &codec->codec_settings.vbr_quality);
+ if (context->codec_settings.vbr) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &context->codec_settings.vbr);
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &context->codec_settings.vbr_quality);
}
- if (codec->codec_settings.abr) {
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &codec->codec_settings.abr);
+ if (context->codec_settings.abr) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &context->codec_settings.abr);
}
- if (codec->codec_settings.dtx) {
- speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &codec->codec_settings.dtx);
+ if (context->codec_settings.dtx) {
+ speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &context->codec_settings.dtx);
}
}
if (decoding) {
speex_bits_init(&context->decoder_bits);
context->decoder_state = speex_decoder_init(mode);
- if (codec->codec_settings.enhancement) {
- speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &codec->codec_settings.enhancement);
+ if (context->codec_settings.enhancement) {
+ speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &context->codec_settings.enhancement);
}
}
@@ -178,7 +270,7 @@ static switch_status_t switch_speex_encode(switch_codec_t *codec,
if (is_speech) {
is_speech = speex_encode_int(context->encoder_state, buf, &context->encoder_bits)
- || !context->codec->codec_settings.dtx;
+ || !context->codec_settings.dtx;
} else {
speex_bits_pack(&context->encoder_bits, 0, 5);
}
@@ -270,6 +362,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_speex_load)
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "Speex");
+ codec_interface->parse_fmtp = switch_speex_fmtp_parse;
for (counta = 1; counta <= 3; counta++) {
for (countb = 1; countb > 0; countb--) {
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt
index ff47780118..19aca46dc8 100644
--- a/src/mod/endpoints/mod_h323/changes.txt
+++ b/src/mod/endpoints/mod_h323/changes.txt
@@ -1,3 +1,4 @@
+fix crashes on FSH323Connection calls in on_hangup routine in different threads.
move PTrace level set to FSH323EndPoint::Initialise
partially apply patch from from Peter Olsson, Remove UnLock() when TryLock() failed and DEBUG_RTP_PACKETS directive.
apply changes from mod_h323-patch.diff by Peter Olsson.
diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp
index aeee422ca5..142506dd92 100644
--- a/src/mod/endpoints/mod_h323/mod_h323.cpp
+++ b/src/mod/endpoints/mod_h323/mod_h323.cpp
@@ -24,7 +24,7 @@
*
* mod_h323.cpp -- H323 endpoint
*
- * Version 0.0.55
+ * Version 0.0.56
*/
//#define DEBUG_RTP_PACKETS
@@ -747,6 +747,17 @@ FSH323Connection::~FSH323Connection()
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_unlock\n");
}
+void FSH323Connection::AttachSignalChannel(const PString & token,
+ H323Transport * channel,
+ PBoolean answeringCall)
+{
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+ tech_pvt->token = strdup((const char *)token);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"---------->token = %s [%p]\n",(const char *)token,this);
+ H323Connection::AttachSignalChannel(token,channel,answeringCall);
+}
+
+
void FSH323Connection::OnSetLocalCapabilities()
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"======>FSH323Connection::OnSetLocalCapabilities() [%p]\n",this);
@@ -2321,8 +2332,9 @@ static switch_status_t on_hangup(switch_core_session_t *session)
switch_channel_t *channel = switch_core_session_get_channel(session);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
FSH323Connection *me = tech_pvt->me;
+ FSH323EndPoint & ep = h323_process->GetH323EndPoint();
tech_pvt->me = NULL;
-
+
if (me) {
if (me->m_rtp_resetting == 1) {
switch_core_session_unlock_codec_read(session);
@@ -2340,12 +2352,12 @@ static switch_status_t on_hangup(switch_core_session_t *session)
me->CloseAllLogicalChannels(false);
me->Unlock();
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"----->%s\n",(const char *)(me->GetCallToken()));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"----->%s\n",(const char *)(tech_pvt->token));
Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);
int trylock = me->TryLock();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"-----> () = %d\n",trylock);
if (trylock == 1) {
- const PString currentToken(me->GetCallToken());
+ const PString currentToken(tech_pvt->token);
FSH323Connection *connection = (FSH323Connection *)me->GetEndPoint()->FindConnectionWithLock(currentToken);
if (connection) {
connection->Unlock();
@@ -2356,8 +2368,10 @@ static switch_status_t on_hangup(switch_core_session_t *session)
} else if (trylock == -1) {
/* Failed to lock - just go on */
}
+ const PString currentToken(tech_pvt->token);
me->SetQ931Cause(cause);
- me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
+// me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
+ ep.ClearCall(currentToken, H323TranslateToCallEndReason(cause, UINT_MAX));
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"------------->h323_mutex_lock\n");
// switch_mutex_lock(tech_pvt->h323_mutex);
}
diff --git a/src/mod/endpoints/mod_h323/mod_h323.h b/src/mod/endpoints/mod_h323/mod_h323.h
index 087540c509..8127206126 100644
--- a/src/mod/endpoints/mod_h323/mod_h323.h
+++ b/src/mod/endpoints/mod_h323/mod_h323.h
@@ -184,6 +184,7 @@ typedef struct {
switch_mutex_t *h323_io_mutex;
FSH323Connection *me;
+ char *token;
} h323_private_t;
#define DECLARE_CALLBACK0(name) \
@@ -306,7 +307,11 @@ class FSH323Connection:public H323Connection {
unsigned callReference, switch_caller_profile_t *outbound_profile,
switch_core_session_t *fsSession, switch_channel_t *fsChannel);
~FSH323Connection();
-
+ virtual void AttachSignalChannel(
+ const PString & token,
+ H323Transport * channel,
+ PBoolean answeringCall
+ );
virtual H323Channel *CreateRealTimeLogicalChannel(const H323Capability & capability,
H323Channel::Directions dir,
unsigned sessionID, const H245_H2250LogicalChannelParameters * param, RTP_QOS * rtpqos = NULL);
diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c
index 8275893be8..ab4db6a1b0 100644
--- a/src/mod/endpoints/mod_loopback/mod_loopback.c
+++ b/src/mod/endpoints/mod_loopback/mod_loopback.c
@@ -52,7 +52,8 @@ typedef enum {
TFLAG_BRIDGE = (1 << 4),
TFLAG_BOWOUT = (1 << 5),
TFLAG_BLEG = (1 << 6),
- TFLAG_APP = (1 << 7)
+ TFLAG_APP = (1 << 7),
+ TFLAG_BOWOUT_USED = (1 << 8)
} TFLAGS;
struct private_object {
@@ -635,7 +636,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
tech_pvt = switch_core_session_get_private(session);
switch_assert(tech_pvt != NULL);
- if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || switch_test_flag(tech_pvt, TFLAG_BOWOUT)) {
+ if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
return SWITCH_STATUS_SUCCESS;
}
@@ -662,6 +663,9 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
switch_clear_flag_locked(tech_pvt, TFLAG_WRITE);
switch_clear_flag_locked(tech_pvt->other_tech_pvt, TFLAG_WRITE);
+ switch_set_flag_locked(tech_pvt, TFLAG_BOWOUT_USED);
+ switch_set_flag_locked(tech_pvt->other_tech_pvt, TFLAG_BOWOUT_USED);
+
if (a_uuid && b_uuid) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel));
diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c
index 165815078b..2df8937647 100644
--- a/src/mod/endpoints/mod_skinny/mod_skinny.c
+++ b/src/mod/endpoints/mod_skinny/mod_skinny.c
@@ -1343,19 +1343,6 @@ static switch_status_t kill_listener(listener_t *listener, void *pvt)
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t kill_expired_listener(listener_t *listener, void *pvt)
-{
- switch_event_t *event = NULL;
-
- if(listener->expire_time < switch_epoch_time_now(NULL)) {
- /* skinny::expire event */
- skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_EXPIRE);
- switch_event_fire(&event);
- return kill_listener(listener, pvt);
- }
- return SWITCH_STATUS_SUCCESS;
-}
-
switch_status_t keepalive_listener(listener_t *listener, void *pvt)
{
skinny_profile_t *profile;
@@ -1414,6 +1401,13 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
case SWITCH_STATUS_TIMEOUT:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Communication Time Out with %s:%d.\n",
listener->remote_ip, listener->remote_port);
+
+ if(listener->expire_time < switch_epoch_time_now(NULL)) {
+ switch_event_t *event = NULL;
+ /* skinny::expire event */
+ skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_EXPIRE);
+ switch_event_fire(&event);
+ }
break;
default:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Communication Error with %s:%d.\n",
@@ -1917,9 +1911,57 @@ static switch_status_t load_skinny_config(void)
return SWITCH_STATUS_SUCCESS;
}
-static void skinny_heartbeat_event_handler(switch_event_t *event)
+static void skinny_user_to_device_event_handler(switch_event_t *event)
{
- walk_listeners(kill_expired_listener, NULL);
+ char *profile_name = switch_event_get_header_nil(event, "Skinny-Profile-Name");
+ skinny_profile_t *profile;
+
+ if ((profile = skinny_find_profile(profile_name))) {
+ char *device_name = switch_event_get_header_nil(event, "Skinny-Device-Name");
+ uint32_t device_instance = atoi(switch_event_get_header_nil(event, "Skinny-Station-Instance"));
+ listener_t *listener = NULL;
+ skinny_profile_find_listener_by_device_name_and_instance(profile, device_name, device_instance, &listener);
+ if(listener) {
+ uint32_t message_type = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id"));
+ uint32_t application_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Application-Id"));
+ uint32_t line_instance = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Line-Instance"));
+ uint32_t call_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Call-Id"));
+ uint32_t transaction_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Transaction-Id"));
+ uint32_t data_length = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Data-Length"));
+ uint32_t sequence_flag = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Sequence-Flag"));
+ uint32_t display_priority = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Display-Priority"));
+ uint32_t conference_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Conference-Id"));
+ uint32_t app_instance_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-App-Instance-Id"));
+ uint32_t routing_id = atoi(switch_event_get_header_nil(event, "Skinny-UserToDevice-Routing-Id"));
+ char *data = switch_event_get_body(event);
+ if (message_type == 0) {
+ message_type = skinny_str2message_type(switch_event_get_header_nil(event, "Skinny-UserToDevice-Message-Id-String"));
+ }
+ switch(message_type) {
+ case USER_TO_DEVICE_DATA_MESSAGE:
+ data_length = strlen(data); /* we ignore data_length sent */
+ send_data(listener, message_type,
+ application_id, line_instance, call_id, transaction_id, data_length,
+ data);
+ case USER_TO_DEVICE_DATA_VERSION1_MESSAGE:
+ data_length = strlen(data); /* we ignore data_length sent */
+ send_extended_data(listener, message_type,
+ application_id, line_instance, call_id, transaction_id, data_length,
+ sequence_flag, display_priority, conference_id, app_instance_id, routing_id,
+ data);
+ break;
+ default:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Incorrect message type %s (%d).\n", skinny_message_type2str(message_type), message_type);
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Device %s:%d in profile '%s' not found.\n", device_name, device_instance, profile_name);
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Profile '%s' not found.\n", profile_name);
+ }
}
static void skinny_call_state_event_handler(switch_event_t *event)
@@ -2129,10 +2171,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
return SWITCH_STATUS_TERM;
}
/* bind to events */
- if ((switch_event_bind_removable(modname, SWITCH_EVENT_HEARTBEAT, NULL, skinny_heartbeat_event_handler, NULL, &globals.heartbeat_node) != SWITCH_STATUS_SUCCESS)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our heartbeat handler!\n");
- /* Not such severe to prevent loading */
- }
if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_CALL_STATE, skinny_call_state_event_handler, NULL, &globals.call_state_node) != SWITCH_STATUS_SUCCESS)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our call_state handler!\n");
return SWITCH_STATUS_TERM;
@@ -2145,6 +2183,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't bind our trap handler!\n");
/* Not such severe to prevent loading */
}
+ if ((switch_event_bind_removable(modname, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE, skinny_user_to_device_event_handler, NULL, &globals.user_to_device_node) != SWITCH_STATUS_SUCCESS)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our user_to_device handler!\n");
+ /* Not such severe to prevent loading */
+ }
/* reserve events */
if (switch_event_reserve_subclass(SKINNY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) {
@@ -2167,6 +2209,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skinny_load)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_CALL_STATE);
return SWITCH_STATUS_TERM;
}
+ if (switch_event_reserve_subclass(SKINNY_EVENT_USER_TO_DEVICE) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_USER_TO_DEVICE);
+ return SWITCH_STATUS_TERM;
+ }
+ if (switch_event_reserve_subclass(SKINNY_EVENT_DEVICE_TO_USER) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", SKINNY_EVENT_DEVICE_TO_USER);
+ return SWITCH_STATUS_TERM;
+ }
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(globals.pool, modname);
@@ -2205,7 +2255,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
skinny_api_unregister();
/* release events */
- switch_event_unbind(&globals.heartbeat_node);
+ switch_event_unbind(&globals.user_to_device_node);
switch_event_unbind(&globals.call_state_node);
switch_event_unbind(&globals.message_waiting_node);
switch_event_unbind(&globals.trap_node);
@@ -2214,6 +2264,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skinny_shutdown)
switch_event_free_subclass(SKINNY_EVENT_EXPIRE);
switch_event_free_subclass(SKINNY_EVENT_ALARM);
switch_event_free_subclass(SKINNY_EVENT_CALL_STATE);
+ switch_event_free_subclass(SKINNY_EVENT_USER_TO_DEVICE);
+ switch_event_free_subclass(SKINNY_EVENT_DEVICE_TO_USER);
switch_mutex_lock(mutex);
diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h
index bbd318b746..b5cc96b7ae 100644
--- a/src/mod/endpoints/mod_skinny/mod_skinny.h
+++ b/src/mod/endpoints/mod_skinny/mod_skinny.h
@@ -43,13 +43,15 @@
#define SKINNY_EVENT_EXPIRE "skinny::expire"
#define SKINNY_EVENT_ALARM "skinny::alarm"
#define SKINNY_EVENT_CALL_STATE "skinny::call_state"
+#define SKINNY_EVENT_USER_TO_DEVICE "skinny::user_to_device"
+#define SKINNY_EVENT_DEVICE_TO_USER "skinny::device_to_user"
struct skinny_globals {
int running;
switch_memory_pool_t *pool;
switch_mutex_t *mutex;
switch_hash_t *profile_hash;
- switch_event_node_t *heartbeat_node;
+ switch_event_node_t *user_to_device_node;
switch_event_node_t *call_state_node;
switch_event_node_t *message_waiting_node;
switch_event_node_t *trap_node;
diff --git a/src/mod/endpoints/mod_skinny/skinny_api.c b/src/mod/endpoints/mod_skinny/skinny_api.c
index 90699d1ad2..7bbb27afd3 100644
--- a/src/mod/endpoints/mod_skinny/skinny_api.c
+++ b/src/mod/endpoints/mod_skinny/skinny_api.c
@@ -366,6 +366,62 @@ static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const ch
return SWITCH_STATUS_SUCCESS;
}
+static switch_status_t skinny_api_cmd_profile_device_send_data(const char *profile_name, const char *device_name, const char *message_type, char *params, const char *body, switch_stream_handle_t *stream)
+{
+ skinny_profile_t *profile;
+
+ if ((profile = skinny_find_profile(profile_name))) {
+ listener_t *listener = NULL;
+ skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
+ if(listener) {
+ switch_event_t *event = NULL;
+ char *argv[64] = { 0 };
+ int argc = 0;
+ int x = 0;
+ /* skinny::user_to_device event */
+ skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Message-Id-String", "%s", message_type);
+ argc = switch_separate_string(params, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+ for (x = 0; x < argc; x++) {
+ char *var_name, *var_value = NULL;
+ var_name = argv[x];
+ if (var_name && (var_value = strchr(var_name, '='))) {
+ *var_value++ = '\0';
+ }
+ if (zstr(var_name)) {
+ stream->write_function(stream, "-ERR No variable specified\n");
+ } else {
+ char *tmp = switch_mprintf("Skinny-UserToDevice-%s", var_name);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, tmp, "%s", var_value);
+ switch_safe_free(tmp);
+ /*
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Application-Id", "%d", request->data.extended_data.application_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Line-Instance", "%d", request->data.extended_data.line_instance);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Call-Id", "%d", request->data.extended_data.call_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Transaction-Id", "%d", request->data.extended_data.transaction_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Data-Length", "%d", request->data.extended_data.data_length);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Sequence-Flag", "%d", request->data.extended_data.sequence_flag);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Display-Priority", "%d", request->data.extended_data.display_priority);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Conference-Id", "%d", request->data.extended_data.conference_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-App-Instance-Id", "%d", request->data.extended_data.app_instance_id);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Routing-Id", "%d", request->data.extended_data.routing_id);
+ */
+ }
+ }
+ switch_event_add_body(event, "%s", body);
+ switch_event_fire(&event);
+ stream->write_function(stream, "+OK\n");
+ } else {
+ stream->write_function(stream, "Listener not found!\n");
+ }
+ } else {
+ stream->write_function(stream, "Profile not found!\n");
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
static switch_status_t skinny_api_cmd_profile_set(const char *profile_name, const char *name, const char *value, switch_stream_handle_t *stream)
{
skinny_profile_t *profile;
@@ -403,6 +459,7 @@ SWITCH_STANDARD_API(skinny_function)
"skinny profile device send SetLampMessage \n"
"skinny profile device send SetSpeakerModeMessage \n"
"skinny profile