~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjmedia/src/pjmedia/tonegen.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: tonegen.c 3664 2011-07-19 03:42:28Z nanang $ */
2
 
/*
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
 */
20
 
#include <pjmedia/tonegen.h>
21
 
#include <pjmedia/errno.h>
22
 
#include <pjmedia/silencedet.h>
23
 
#include <pj/assert.h>
24
 
#include <pj/ctype.h>
25
 
#include <pj/lock.h>
26
 
#include <pj/log.h>
27
 
#include <pj/pool.h>
28
 
 
29
 
/* amplitude */
30
 
#define AMP     PJMEDIA_TONEGEN_VOLUME
31
 
 
32
 
#ifndef M_PI
33
 
#   define M_PI  ((DATA)3.141592653589793238462643383279)
34
 
#endif
35
 
 
36
 
#if PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_SINE
37
 
    #include <math.h>
38
 
    #define DATA        double
39
 
 
40
 
    /*
41
 
     * This is the good old tone generator using sin().
42
 
     * Speed = 1347 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
43
 
     *         approx. 10.91 MIPS
44
 
     *
45
 
     *         506,535 usec/100.29 MIPS on ARM926EJ-S.
46
 
     */
47
 
    struct gen
48
 
    {
49
 
        DATA add;
50
 
        DATA c;
51
 
        DATA vol;
52
 
    };
53
 
 
54
 
    #define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A
55
 
    #define GEN_SAMP(val,var)   val = (short)(sin(var.c * 2 * M_PI) * \
56
 
                                              var.vol); \
57
 
                                var.c += var.add
58
 
 
59
 
#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FLOATING_POINT
60
 
    #include <math.h>
61
 
    #define DATA        float
62
 
 
63
 
    /*
64
 
     * Default floating-point based tone generation using sine wave
65
 
     * generation from:
66
 
     *   http://www.musicdsp.org/showone.php?id=10.
67
 
     * This produces good quality tone in relatively faster time than
68
 
     * the normal sin() generator.
69
 
     * Speed = 350 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
70
 
     *         approx. 2.84 MIPS
71
 
     *
72
 
     *         18,037 usec/3.57 MIPS on ARM926EJ-S.
73
 
     */
74
 
    struct gen
75
 
    {
76
 
        DATA a, s0, s1;
77
 
    };
78
 
 
79
 
    #define GEN_INIT(var,R,F,A) var.a = (DATA) (2.0 * sin(M_PI * F / R)); \
80
 
                                var.s0 = 0; \
81
 
                                var.s1 = (DATA)(0 - (int)A)
82
 
    #define GEN_SAMP(val,var)   var.s0 = var.s0 - var.a * var.s1; \
83
 
                                var.s1 = var.s1 + var.a * var.s0; \
84
 
                                val = (short) var.s0
85
 
 
86
 
#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FIXED_POINT_CORDIC
87
 
    /* Cordic algorithm with 28 bit size, from:
88
 
     * http://www.dcs.gla.ac.uk/~jhw/cordic/
89
 
     * Speed = 742 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
90
 
     *         (PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP=7)
91
 
     *         approx. 6.01 MIPS
92
 
     *
93
 
     *         ARM926EJ-S results:
94
 
     *          loop=7:   8,943 usec/1.77 MIPS
95
 
     *          loop=8:   9,872 usec/1.95 MIPS
96
 
     *          loop=10: 11,662 usec/2.31 MIPS
97
 
     *          loop=12: 13,561 usec/2.69 MIPS
98
 
     */
99
 
    #define CORDIC_1K           0x026DD3B6
100
 
    #define CORDIC_HALF_PI      0x06487ED5
101
 
    #define CORDIC_PI           (CORDIC_HALF_PI * 2)
102
 
    #define CORDIC_MUL_BITS     26
103
 
    #define CORDIC_MUL          (1 << CORDIC_MUL_BITS)
104
 
    #define CORDIC_NTAB         28
105
 
    #define CORDIC_LOOP         PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP
106
 
 
107
 
    static int cordic_ctab [] =
108
 
    {
109
 
        0x03243F6A, 0x01DAC670, 0x00FADBAF, 0x007F56EA, 0x003FEAB7,
110
 
        0x001FFD55, 0x000FFFAA, 0x0007FFF5, 0x0003FFFE, 0x0001FFFF,
111
 
        0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF,
112
 
        0x000007FF, 0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F,
113
 
        0x0000003F, 0x0000001F, 0x0000000F, 0x00000007, 0x00000003,
114
 
        0x00000001, 0x00000000, 0x00000000
115
 
    };
116
 
 
117
 
    static pj_int32_t cordic(pj_int32_t theta, unsigned n)
118
 
    {
119
 
        unsigned k;
120
 
        int d;
121
 
        pj_int32_t tx;
122
 
        pj_int32_t x = CORDIC_1K, y = 0, z = theta;
123
 
 
124
 
        for (k=0; k<n; ++k) {
125
 
            #if 0
126
 
            d = (z>=0) ? 0 : -1;
127
 
            #else
128
 
            /* Only slightly (~2.5%) faster, but not portable? */
129
 
             d = z>>27;
130
 
            #endif
131
 
            tx = x - (((y>>k) ^ d) - d);
132
 
            y = y + (((x>>k) ^ d) - d);
133
 
            z = z - ((cordic_ctab[k] ^ d) - d);
134
 
            x = tx;
135
 
        }
136
 
        return y;
137
 
    }
138
 
 
139
 
    /* Note: theta must be uint32 here */
140
 
    static pj_int32_t cordic_sin(pj_uint32_t theta, unsigned n)
141
 
    {
142
 
        if (theta < CORDIC_HALF_PI)
143
 
            return cordic(theta, n);
144
 
        else if (theta < CORDIC_PI)
145
 
            return cordic(CORDIC_HALF_PI-(theta-CORDIC_HALF_PI), n);
146
 
        else if (theta < CORDIC_PI + CORDIC_HALF_PI)
147
 
            return -cordic(theta - CORDIC_PI, n);
148
 
        else if (theta < 2 * CORDIC_PI)
149
 
            return -cordic(CORDIC_HALF_PI-(theta-3*CORDIC_HALF_PI), n);
150
 
        else {
151
 
            pj_assert(!"Invalid cordic_sin() value");
152
 
            return 0;
153
 
        }
154
 
    }
155
 
 
156
 
    struct gen
157
 
    {
158
 
        unsigned    add;
159
 
        pj_uint32_t c;
160
 
        unsigned    vol;
161
 
    };
162
 
 
163
 
    #define VOL(var,v)          (((v) * var.vol) >> 15)
164
 
    #define GEN_INIT(var,R,F,A) gen_init(&var, R, F, A)
165
 
    #define GEN_SAMP(val,var)   val = gen_samp(&var)
166
 
 
167
 
    static void gen_init(struct gen *var, unsigned R, unsigned F, unsigned A)
168
 
    {
169
 
        var->add = 2*CORDIC_PI/R * F;
170
 
        var->c = 0;
171
 
        var->vol = A;
172
 
    }
173
 
 
174
 
    PJ_INLINE(short) gen_samp(struct gen *var)
175
 
    {
176
 
        pj_int32_t val;
177
 
        val = cordic_sin(var->c, CORDIC_LOOP);
178
 
        /*val = (val * 32767) / CORDIC_MUL;
179
 
         *val = VOL((*var), val);
180
 
         */
181
 
        val = ((val >> 10) * var->vol) >> 16;
182
 
        var->c += var->add;
183
 
        if (var->c > 2*CORDIC_PI)
184
 
            var->c -= (2 * CORDIC_PI);
185
 
        return (short) val;
186
 
    }
187
 
 
188
 
#elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FAST_FIXED_POINT
189
 
 
190
 
    /*
191
 
     * Fallback algorithm when floating point is disabled.
192
 
     * This is a very fast fixed point tone generation using sine wave
193
 
     * approximation from
194
 
     *    http://www.audiomulch.com/~rossb/code/sinusoids/
195
 
     * Quality wise not so good, but it's blazing fast!
196
 
     * Speed = 117 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
197
 
     *         approx. 0.95 MIPS
198
 
     *
199
 
     *         1,449 usec/0.29 MIPS on ARM926EJ-S.
200
 
     */
201
 
    PJ_INLINE(int) approximate_sin3(unsigned x)
202
 
    {
203
 
            unsigned s=-(int)(x>>31);
204
 
            x+=x;
205
 
            x=x>>16;
206
 
            x*=x^0xffff;            // x=x*(2-x)
207
 
            x+=x;                   // optional
208
 
            return x^s;
209
 
    }
210
 
    struct gen
211
 
    {
212
 
        unsigned add;
213
 
        unsigned c;
214
 
        unsigned vol;
215
 
    };
216
 
 
217
 
    #define MAXI                ((unsigned)0xFFFFFFFF)
218
 
    #define SIN                 approximate_sin3
219
 
    #define VOL(var,v)          (((v) * var.vol) >> 15)
220
 
    #define GEN_INIT(var,R,F,A) var.add = MAXI/R * F, var.c=0, var.vol=A
221
 
    #define GEN_SAMP(val,var)   val = (short) VOL(var,SIN(var.c)>>16); \
222
 
                                var.c += var.add
223
 
 
224
 
#else
225
 
    #error "PJMEDIA_TONEGEN_ALG is not set correctly"
226
 
#endif
227
 
 
228
 
struct gen_state
229
 
{
230
 
    struct gen tone1;
231
 
    struct gen tone2;
232
 
    pj_bool_t  has_tone2;
233
 
};
234
 
 
235
 
 
236
 
static void init_generate_single_tone(struct gen_state *state,
237
 
                                      unsigned clock_rate,
238
 
                                      unsigned freq,
239
 
                                      unsigned vol)
240
 
{
241
 
    GEN_INIT(state->tone1,clock_rate,freq,vol);
242
 
    state->has_tone2 = PJ_FALSE;
243
 
}
244
 
 
245
 
static void generate_single_tone(struct gen_state *state,
246
 
                                 unsigned channel_count,
247
 
                                 unsigned samples,
248
 
                                 short buf[])
249
 
{
250
 
    short *end = buf + samples;
251
 
 
252
 
    if (channel_count==1) {
253
 
 
254
 
        while (buf < end) {
255
 
            GEN_SAMP(*buf++, state->tone1);
256
 
        }
257
 
 
258
 
    } else if (channel_count == 2) {
259
 
 
260
 
        while (buf < end) {
261
 
            GEN_SAMP(*buf, state->tone1);
262
 
            *(buf+1) = *buf;
263
 
            buf += 2;
264
 
        }
265
 
    }
266
 
}
267
 
 
268
 
 
269
 
static void init_generate_dual_tone(struct gen_state *state,
270
 
                                    unsigned clock_rate,
271
 
                                    unsigned freq1,
272
 
                                    unsigned freq2,
273
 
                                    unsigned vol)
274
 
{
275
 
    GEN_INIT(state->tone1,clock_rate,freq1,vol);
276
 
    GEN_INIT(state->tone2,clock_rate,freq2,vol);
277
 
    state->has_tone2 = PJ_TRUE;
278
 
}
279
 
 
280
 
 
281
 
static void generate_dual_tone(struct gen_state *state,
282
 
                               unsigned channel_count,
283
 
                               unsigned samples,
284
 
                               short buf[])
285
 
{
286
 
    short *end = buf + samples;
287
 
 
288
 
    if (channel_count==1) {
289
 
        int val, val2;
290
 
        while (buf < end) {
291
 
            GEN_SAMP(val, state->tone1);
292
 
            GEN_SAMP(val2, state->tone2);
293
 
            *buf++ = (short)((val+val2) >> 1);
294
 
        }
295
 
    } else if (channel_count == 2) {
296
 
        int val, val2;
297
 
        while (buf < end) {
298
 
 
299
 
            GEN_SAMP(val, state->tone1);
300
 
            GEN_SAMP(val2, state->tone2);
301
 
            val = (val + val2) >> 1;
302
 
 
303
 
            *buf++ = (short)val;
304
 
            *buf++ = (short)val;
305
 
        }
306
 
    }
307
 
}
308
 
 
309
 
 
310
 
static void init_generate_tone(struct gen_state *state,
311
 
                               unsigned clock_rate,
312
 
                               unsigned freq1,
313
 
                               unsigned freq2,
314
 
                               unsigned vol)
315
 
{
316
 
    if (freq2)
317
 
        init_generate_dual_tone(state, clock_rate, freq1, freq2 ,vol);
318
 
    else
319
 
        init_generate_single_tone(state, clock_rate, freq1,vol);
320
 
}
321
 
 
322
 
 
323
 
static void generate_tone(struct gen_state *state,
324
 
                          unsigned channel_count,
325
 
                          unsigned samples,
326
 
                          short buf[])
327
 
{
328
 
    if (!state->has_tone2)
329
 
        generate_single_tone(state, channel_count, samples, buf);
330
 
    else
331
 
        generate_dual_tone(state, channel_count, samples, buf);
332
 
}
333
 
 
334
 
 
335
 
/****************************************************************************/
336
 
 
337
 
#define SIGNATURE   PJMEDIA_SIG_PORT_TONEGEN
338
 
#define THIS_FILE   "tonegen.c"
339
 
 
340
 
#if 0
341
 
#   define TRACE_(expr) PJ_LOG(4,expr)
342
 
#else
343
 
#   define TRACE_(expr)
344
 
#endif
345
 
 
346
 
enum flags
347
 
{
348
 
    PJMEDIA_TONE_INITIALIZED    = 1,
349
 
    PJMEDIA_TONE_ENABLE_FADE    = 2
350
 
};
351
 
 
352
 
struct tonegen
353
 
{
354
 
    pjmedia_port        base;
355
 
 
356
 
    /* options */
357
 
    unsigned            options;
358
 
    unsigned            playback_options;
359
 
    unsigned            fade_in_len;    /* fade in for this # of samples */
360
 
    unsigned            fade_out_len;   /* fade out for this # of samples*/
361
 
 
362
 
    /* lock */
363
 
    pj_lock_t          *lock;
364
 
 
365
 
    /* Digit map */
366
 
    pjmedia_tone_digit_map  *digit_map;
367
 
 
368
 
    /* Tone generation state */
369
 
    struct gen_state    state;
370
 
 
371
 
    /* Currently played digits: */
372
 
    unsigned            count;              /* # of digits              */
373
 
    unsigned            cur_digit;          /* currently played         */
374
 
    unsigned            dig_samples;        /* sample pos in cur digit  */
375
 
    pjmedia_tone_desc   digits[PJMEDIA_TONEGEN_MAX_DIGITS];/* array of digits*/
376
 
};
377
 
 
378
 
 
379
 
/* Default digit map is DTMF */
380
 
static pjmedia_tone_digit_map digit_map =
381
 
{
382
 
    16,
383
 
    {
384
 
        { '0', 941,  1336 },
385
 
        { '1', 697,  1209 },
386
 
        { '2', 697,  1336 },
387
 
        { '3', 697,  1477 },
388
 
        { '4', 770,  1209 },
389
 
        { '5', 770,  1336 },
390
 
        { '6', 770,  1477 },
391
 
        { '7', 852,  1209 },
392
 
        { '8', 852,  1336 },
393
 
        { '9', 852,  1477 },
394
 
        { 'a', 697,  1633 },
395
 
        { 'b', 770,  1633 },
396
 
        { 'c', 852,  1633 },
397
 
        { 'd', 941,  1633 },
398
 
        { '*', 941,  1209 },
399
 
        { '#', 941,  1477 },
400
 
    }
401
 
};
402
 
 
403
 
 
404
 
static pj_status_t tonegen_get_frame(pjmedia_port *this_port,
405
 
                                     pjmedia_frame *frame);
406
 
static pj_status_t tonegen_destroy(pjmedia_port *this_port);
407
 
 
408
 
/*
409
 
 * Create an instance of tone generator with the specified parameters.
410
 
 * When the tone generator is first created, it will be loaded with the
411
 
 * default digit map.
412
 
 */
413
 
PJ_DEF(pj_status_t) pjmedia_tonegen_create2(pj_pool_t *pool,
414
 
                                            const pj_str_t *name,
415
 
                                            unsigned clock_rate,
416
 
                                            unsigned channel_count,
417
 
                                            unsigned samples_per_frame,
418
 
                                            unsigned bits_per_sample,
419
 
                                            unsigned options,
420
 
                                            pjmedia_port **p_port)
421
 
{
422
 
    const pj_str_t STR_TONE_GEN = pj_str("tonegen");
423
 
    struct tonegen  *tonegen;
424
 
    pj_status_t status;
425
 
 
426
 
    PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
427
 
                     samples_per_frame && bits_per_sample == 16 &&
428
 
                     p_port != NULL, PJ_EINVAL);
429
 
 
430
 
    /* Only support mono and stereo */
431
 
    PJ_ASSERT_RETURN(channel_count==1 || channel_count==2, PJ_EINVAL);
432
 
 
433
 
    /* Create and initialize port */
434
 
    tonegen = PJ_POOL_ZALLOC_T(pool, struct tonegen);
435
 
    if (name == NULL || name->slen == 0) name = &STR_TONE_GEN;
436
 
    status = pjmedia_port_info_init(&tonegen->base.info, name,
437
 
                                    SIGNATURE, clock_rate, channel_count,
438
 
                                    bits_per_sample, samples_per_frame);
439
 
    if (status != PJ_SUCCESS)
440
 
        return status;
441
 
 
442
 
    tonegen->options = options;
443
 
    tonegen->base.get_frame = &tonegen_get_frame;
444
 
    tonegen->base.on_destroy = &tonegen_destroy;
445
 
    tonegen->digit_map = &digit_map;
446
 
 
447
 
    tonegen->fade_in_len = PJMEDIA_TONEGEN_FADE_IN_TIME * clock_rate / 1000;
448
 
    tonegen->fade_out_len = PJMEDIA_TONEGEN_FADE_OUT_TIME * clock_rate / 1000;
449
 
 
450
 
    /* Lock */
451
 
    if (options & PJMEDIA_TONEGEN_NO_LOCK) {
452
 
        status = pj_lock_create_null_mutex(pool, "tonegen", &tonegen->lock);
453
 
    } else {
454
 
        status = pj_lock_create_simple_mutex(pool, "tonegen", &tonegen->lock);
455
 
    }
456
 
 
457
 
    if (status != PJ_SUCCESS) {
458
 
        return status;
459
 
    }
460
 
 
461
 
    TRACE_((THIS_FILE, "Tonegen created: %u/%u/%u/%u", clock_rate,
462
 
            channel_count, samples_per_frame, bits_per_sample));
463
 
 
464
 
    /* Done */
465
 
    *p_port = &tonegen->base;
466
 
    return PJ_SUCCESS;
467
 
}
468
 
 
469
 
 
470
 
PJ_DEF(pj_status_t) pjmedia_tonegen_create( pj_pool_t *pool,
471
 
                                            unsigned clock_rate,
472
 
                                            unsigned channel_count,
473
 
                                            unsigned samples_per_frame,
474
 
                                            unsigned bits_per_sample,
475
 
                                            unsigned options,
476
 
                                            pjmedia_port **p_port)
477
 
{
478
 
    return pjmedia_tonegen_create2(pool, NULL, clock_rate, channel_count,
479
 
                                   samples_per_frame, bits_per_sample,
480
 
                                   options, p_port);
481
 
}
482
 
 
483
 
 
484
 
/*
485
 
 * Check if the tone generator is still busy producing some tones.
486
 
 */
487
 
PJ_DEF(pj_bool_t) pjmedia_tonegen_is_busy(pjmedia_port *port)
488
 
{
489
 
    struct tonegen *tonegen = (struct tonegen*) port;
490
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_TRUE);
491
 
    return tonegen->count != 0;
492
 
}
493
 
 
494
 
 
495
 
/*
496
 
 * Instruct the tone generator to stop current processing.
497
 
 */
498
 
PJ_DEF(pj_status_t) pjmedia_tonegen_stop(pjmedia_port *port)
499
 
{
500
 
    struct tonegen *tonegen = (struct tonegen*) port;
501
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
502
 
 
503
 
    TRACE_((THIS_FILE, "tonegen_stop()"));
504
 
 
505
 
    pj_lock_acquire(tonegen->lock);
506
 
    tonegen->count = 0;
507
 
    tonegen->cur_digit = 0;
508
 
    tonegen->dig_samples = 0;
509
 
    pj_lock_release(tonegen->lock);
510
 
 
511
 
    return PJ_SUCCESS;
512
 
}
513
 
 
514
 
 
515
 
/*
516
 
 * Instruct the tone generator to stop current processing.
517
 
 */
518
 
PJ_DEF(pj_status_t) pjmedia_tonegen_rewind(pjmedia_port *port)
519
 
{
520
 
    struct tonegen *tonegen = (struct tonegen*) port;
521
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
522
 
 
523
 
    TRACE_((THIS_FILE, "tonegen_rewind()"));
524
 
 
525
 
    /* Reset back to the first tone */
526
 
    pj_lock_acquire(tonegen->lock);
527
 
    tonegen->cur_digit = 0;
528
 
    tonegen->dig_samples = 0;
529
 
    pj_lock_release(tonegen->lock);
530
 
 
531
 
    return PJ_SUCCESS;
532
 
}
533
 
 
534
 
 
535
 
/*
536
 
 * Callback to destroy tonegen
537
 
 */
538
 
static pj_status_t tonegen_destroy(pjmedia_port *port)
539
 
{
540
 
    struct tonegen *tonegen = (struct tonegen*) port;
541
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
542
 
 
543
 
    TRACE_((THIS_FILE, "tonegen_destroy()"));
544
 
 
545
 
    pj_lock_acquire(tonegen->lock);
546
 
    pj_lock_release(tonegen->lock);
547
 
 
548
 
    pj_lock_destroy(tonegen->lock);
549
 
 
550
 
    return PJ_SUCCESS;
551
 
}
552
 
 
553
 
/*
554
 
 * Fill a frame with tones.
555
 
 */
556
 
static pj_status_t tonegen_get_frame(pjmedia_port *port,
557
 
                                     pjmedia_frame *frame)
558
 
{
559
 
    struct tonegen *tonegen = (struct tonegen*) port;
560
 
    short *dst, *end;
561
 
    unsigned clock_rate = PJMEDIA_PIA_SRATE(&tonegen->base.info);
562
 
 
563
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
564
 
 
565
 
    pj_lock_acquire(tonegen->lock);
566
 
 
567
 
    if (tonegen->count == 0) {
568
 
        /* We don't have digits to play */
569
 
        frame->type = PJMEDIA_FRAME_TYPE_NONE;
570
 
        goto on_return;
571
 
    }
572
 
 
573
 
    if (tonegen->cur_digit > tonegen->count) {
574
 
        /* We have played all the digits */
575
 
        if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
576
 
        {
577
 
            /* Reset back to the first tone */
578
 
            tonegen->cur_digit = 0;
579
 
            tonegen->dig_samples = 0;
580
 
 
581
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
582
 
 
583
 
        } else {
584
 
            tonegen->count = 0;
585
 
            tonegen->cur_digit = 0;
586
 
            frame->type = PJMEDIA_FRAME_TYPE_NONE;
587
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
588
 
            goto on_return;
589
 
        }
590
 
    }
591
 
 
592
 
    if (tonegen->dig_samples>=(tonegen->digits[tonegen->cur_digit].on_msec+
593
 
                               tonegen->digits[tonegen->cur_digit].off_msec)*
594
 
                               clock_rate / 1000)
595
 
    {
596
 
        /* We have finished with current digit */
597
 
        tonegen->cur_digit++;
598
 
        tonegen->dig_samples = 0;
599
 
 
600
 
        TRACE_((THIS_FILE, "tonegen_get_frame(): next digit"));
601
 
    }
602
 
 
603
 
    if (tonegen->cur_digit >= tonegen->count) {
604
 
        /* After we're finished with the last digit, we have played all
605
 
         * the digits
606
 
         */
607
 
        if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
608
 
        {
609
 
            /* Reset back to the first tone */
610
 
            tonegen->cur_digit = 0;
611
 
            tonegen->dig_samples = 0;
612
 
 
613
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
614
 
 
615
 
        } else {
616
 
            tonegen->count = 0;
617
 
            tonegen->cur_digit = 0;
618
 
            frame->type = PJMEDIA_FRAME_TYPE_NONE;
619
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
620
 
            goto on_return;
621
 
        }
622
 
    }
623
 
 
624
 
    dst = (short*) frame->buf;
625
 
    end = dst + PJMEDIA_PIA_SPF(&port->info);
626
 
 
627
 
    while (dst < end) {
628
 
        pjmedia_tone_desc *dig = &tonegen->digits[tonegen->cur_digit];
629
 
        unsigned required, cnt, on_samp, off_samp;
630
 
 
631
 
        required = end - dst;
632
 
        on_samp = dig->on_msec * clock_rate / 1000;
633
 
        off_samp = dig->off_msec * clock_rate / 1000;
634
 
 
635
 
        /* Init tonegen */
636
 
        if (tonegen->dig_samples == 0 &&
637
 
            (tonegen->count!=1 || !(dig->flags & PJMEDIA_TONE_INITIALIZED)))
638
 
        {
639
 
            init_generate_tone(&tonegen->state,
640
 
                               PJMEDIA_PIA_SRATE(&port->info),
641
 
                               dig->freq1, dig->freq2, dig->volume);
642
 
            dig->flags |= PJMEDIA_TONE_INITIALIZED;
643
 
            if (tonegen->cur_digit > 0) {
644
 
                /* Clear initialized flag of previous digit */
645
 
                tonegen->digits[tonegen->cur_digit-1].flags &=
646
 
                                                (~PJMEDIA_TONE_INITIALIZED);
647
 
            }
648
 
        }
649
 
 
650
 
        /* Add tone signal */
651
 
        if (tonegen->dig_samples < on_samp) {
652
 
            cnt = on_samp - tonegen->dig_samples;
653
 
            if (cnt > required)
654
 
                cnt = required;
655
 
            generate_tone(&tonegen->state,
656
 
                          PJMEDIA_PIA_CCNT(&port->info),
657
 
                          cnt, dst);
658
 
 
659
 
            dst += cnt;
660
 
            tonegen->dig_samples += cnt;
661
 
            required -= cnt;
662
 
 
663
 
            if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
664
 
                tonegen->dig_samples == cnt)
665
 
            {
666
 
                /* Fade in */
667
 
                short *samp = (dst - cnt);
668
 
                short *end;
669
 
 
670
 
                if (cnt > tonegen->fade_in_len)
671
 
                    cnt = tonegen->fade_in_len;
672
 
                end = samp + cnt;
673
 
                if (cnt) {
674
 
                    const unsigned step = 0xFFFF / cnt;
675
 
                    unsigned scale = 0;
676
 
 
677
 
                    for (; samp < end; ++samp) {
678
 
                        (*samp) = (short)(((*samp) * scale) >> 16);
679
 
                        scale += step;
680
 
                    }
681
 
                }
682
 
            } else if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
683
 
                        tonegen->dig_samples==on_samp)
684
 
            {
685
 
                /* Fade out */
686
 
                if (cnt > tonegen->fade_out_len)
687
 
                    cnt = tonegen->fade_out_len;
688
 
                if (cnt) {
689
 
                    short *samp = (dst - cnt);
690
 
                    const unsigned step = 0xFFFF / cnt;
691
 
                    unsigned scale = 0xFFFF - step;
692
 
 
693
 
                    for (; samp < dst; ++samp) {
694
 
                        (*samp) = (short)(((*samp) * scale) >> 16);
695
 
                        scale -= step;
696
 
                    }
697
 
                }
698
 
            }
699
 
 
700
 
            if (dst == end)
701
 
                break;
702
 
        }
703
 
 
704
 
        /* Add silence signal */
705
 
        cnt = off_samp + on_samp - tonegen->dig_samples;
706
 
        if (cnt > required)
707
 
            cnt = required;
708
 
        pjmedia_zero_samples(dst, cnt);
709
 
        dst += cnt;
710
 
        tonegen->dig_samples += cnt;
711
 
 
712
 
        /* Move to next digit if we're finished with this tone */
713
 
        if (tonegen->dig_samples >= on_samp + off_samp) {
714
 
            tonegen->cur_digit++;
715
 
            tonegen->dig_samples = 0;
716
 
 
717
 
            if (tonegen->cur_digit >= tonegen->count) {
718
 
                /* All digits have been played */
719
 
                if ((tonegen->options & PJMEDIA_TONEGEN_LOOP) ||
720
 
                    (tonegen->playback_options & PJMEDIA_TONEGEN_LOOP))
721
 
                {
722
 
                    tonegen->cur_digit = 0;
723
 
                } else {
724
 
                    break;
725
 
                }
726
 
            }
727
 
        }
728
 
    }
729
 
 
730
 
    if (dst < end)
731
 
        pjmedia_zero_samples(dst, end-dst);
732
 
 
733
 
    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
734
 
    frame->size = PJMEDIA_PIA_AVG_FSZ(&port->info);
735
 
 
736
 
    TRACE_((THIS_FILE, "tonegen_get_frame(): frame created, level=%u",
737
 
            pjmedia_calc_avg_signal((pj_int16_t*)frame->buf, frame->size/2)));
738
 
 
739
 
    if (tonegen->cur_digit >= tonegen->count) {
740
 
        if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
741
 
        {
742
 
            /* Reset back to the first tone */
743
 
            tonegen->cur_digit = 0;
744
 
            tonegen->dig_samples = 0;
745
 
 
746
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
747
 
 
748
 
        } else {
749
 
            tonegen->count = 0;
750
 
            tonegen->cur_digit = 0;
751
 
 
752
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
753
 
        }
754
 
    }
755
 
 
756
 
on_return:
757
 
    pj_lock_release(tonegen->lock);
758
 
    return PJ_SUCCESS;
759
 
}
760
 
 
761
 
 
762
 
/*
763
 
 * Play tones.
764
 
 */
765
 
PJ_DEF(pj_status_t) pjmedia_tonegen_play( pjmedia_port *port,
766
 
                                          unsigned count,
767
 
                                          const pjmedia_tone_desc tones[],
768
 
                                          unsigned options)
769
 
{
770
 
    struct tonegen *tonegen = (struct tonegen*) port;
771
 
    unsigned i;
772
 
 
773
 
    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
774
 
                     count && tones, PJ_EINVAL);
775
 
 
776
 
    /* Don't put more than available buffer */
777
 
    PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
778
 
                     PJ_ETOOMANY);
779
 
 
780
 
    pj_lock_acquire(tonegen->lock);
781
 
 
782
 
    /* Set playback options */
783
 
    tonegen->playback_options = options;
784
 
 
785
 
    /* Copy digits */
786
 
    pj_memcpy(tonegen->digits + tonegen->count,
787
 
              tones, count * sizeof(pjmedia_tone_desc));
788
 
 
789
 
    /* Normalize volume, and check if we need to disable fading.
790
 
     * Disable fading if tone off time is zero. Application probably
791
 
     * wants to play this tone continuously (e.g. dial tone).
792
 
     */
793
 
    for (i=0; i<count; ++i) {
794
 
        pjmedia_tone_desc *t = &tonegen->digits[i+tonegen->count];
795
 
        if (t->volume == 0)
796
 
            t->volume = AMP;
797
 
        else if (t->volume < 0)
798
 
            t->volume = (short) -t->volume;
799
 
        /* Reset flags */
800
 
        t->flags = 0;
801
 
        if (t->off_msec != 0)
802
 
            t->flags |= PJMEDIA_TONE_ENABLE_FADE;
803
 
    }
804
 
 
805
 
    tonegen->count += count;
806
 
 
807
 
    pj_lock_release(tonegen->lock);
808
 
 
809
 
    return PJ_SUCCESS;
810
 
}
811
 
 
812
 
 
813
 
/*
814
 
 * Play digits.
815
 
 */
816
 
PJ_DEF(pj_status_t) pjmedia_tonegen_play_digits( pjmedia_port *port,
817
 
                                                 unsigned count,
818
 
                                                 const pjmedia_tone_digit digits[],
819
 
                                                 unsigned options)
820
 
{
821
 
    struct tonegen *tonegen = (struct tonegen*) port;
822
 
    pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
823
 
    const pjmedia_tone_digit_map *map;
824
 
    unsigned i;
825
 
 
826
 
    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
827
 
                     count && digits, PJ_EINVAL);
828
 
    PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);
829
 
 
830
 
    pj_lock_acquire(tonegen->lock);
831
 
 
832
 
    map = tonegen->digit_map;
833
 
 
834
 
    for (i=0; i<count; ++i) {
835
 
        int d = pj_tolower(digits[i].digit);
836
 
        unsigned j;
837
 
 
838
 
        /* Translate ASCII digits with digitmap */
839
 
        for (j=0; j<map->count; ++j) {
840
 
            if (d == map->digits[j].digit)
841
 
                break;
842
 
        }
843
 
        if (j == map->count) {
844
 
            pj_lock_release(tonegen->lock);
845
 
            return PJMEDIA_RTP_EINDTMF;
846
 
        }
847
 
 
848
 
        tones[i].freq1 = map->digits[j].freq1;
849
 
        tones[i].freq2 = map->digits[j].freq2;
850
 
        tones[i].on_msec = digits[i].on_msec;
851
 
        tones[i].off_msec = digits[i].off_msec;
852
 
        tones[i].volume = digits[i].volume;
853
 
    }
854
 
 
855
 
    pj_lock_release(tonegen->lock);
856
 
 
857
 
    return pjmedia_tonegen_play(port, count, tones, options);
858
 
}
859
 
 
860
 
 
861
 
/*
862
 
 * Get the digit-map currently used by this tone generator.
863
 
 */
864
 
PJ_DEF(pj_status_t) pjmedia_tonegen_get_digit_map(pjmedia_port *port,
865
 
                                                  const pjmedia_tone_digit_map **m)
866
 
{
867
 
    struct tonegen *tonegen = (struct tonegen*) port;
868
 
 
869
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
870
 
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
871
 
 
872
 
    *m = tonegen->digit_map;
873
 
 
874
 
    return PJ_SUCCESS;
875
 
}
876
 
 
877
 
 
878
 
/*
879
 
 * Set digit map to be used by the tone generator.
880
 
 */
881
 
PJ_DEF(pj_status_t) pjmedia_tonegen_set_digit_map(pjmedia_port *port,
882
 
                                                  pjmedia_tone_digit_map *m)
883
 
{
884
 
    struct tonegen *tonegen = (struct tonegen*) port;
885
 
 
886
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
887
 
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
888
 
 
889
 
    pj_lock_acquire(tonegen->lock);
890
 
 
891
 
    tonegen->digit_map = m;
892
 
 
893
 
    pj_lock_release(tonegen->lock);
894
 
 
895
 
    return PJ_SUCCESS;
896
 
}