~ubuntu-branches/debian/sid/sflphone/sid

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-02 18:04:11 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130602180411-3rcpy8c1zdlo8y0s
Tags: 1.2.2-1
* New upstream release
* changeset_rb68857a4b485b7d43f92714cd5792595ff895f82.diff - fix QTest
* pjproject ./configure --disable-sound --disable-video

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: tonegen.c 3553 2011-05-05 06:14:19Z 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_PORT_SIGNATURE('t', 'n', 'g', 'n')
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 = tonegen->base.info.clock_rate;
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 + port->info.samples_per_frame;
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, port->info.clock_rate,
640
 
                               dig->freq1, dig->freq2, dig->volume);
641
 
            dig->flags |= PJMEDIA_TONE_INITIALIZED;
642
 
            if (tonegen->cur_digit > 0) {
643
 
                /* Clear initialized flag of previous digit */
644
 
                tonegen->digits[tonegen->cur_digit-1].flags &= 
645
 
                                                (~PJMEDIA_TONE_INITIALIZED);
646
 
            }
647
 
        }
648
 
 
649
 
        /* Add tone signal */
650
 
        if (tonegen->dig_samples < on_samp) {
651
 
            cnt = on_samp - tonegen->dig_samples;
652
 
            if (cnt > required)
653
 
                cnt = required;
654
 
            generate_tone(&tonegen->state, port->info.channel_count,
655
 
                          cnt, dst);
656
 
 
657
 
            dst += cnt;
658
 
            tonegen->dig_samples += cnt;
659
 
            required -= cnt;
660
 
 
661
 
            if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) && 
662
 
                tonegen->dig_samples == cnt) 
663
 
            {
664
 
                /* Fade in */
665
 
                short *samp = (dst - cnt);
666
 
                short *end;
667
 
 
668
 
                if (cnt > tonegen->fade_in_len)
669
 
                    cnt = tonegen->fade_in_len;
670
 
                end = samp + cnt;
671
 
                if (cnt) {
672
 
                    const unsigned step = 0xFFFF / cnt;
673
 
                    unsigned scale = 0;
674
 
 
675
 
                    for (; samp < end; ++samp) {
676
 
                        (*samp) = (short)(((*samp) * scale) >> 16);
677
 
                        scale += step;
678
 
                    }
679
 
                }
680
 
            } else if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
681
 
                        tonegen->dig_samples==on_samp) 
682
 
            {
683
 
                /* Fade out */
684
 
                if (cnt > tonegen->fade_out_len)
685
 
                    cnt = tonegen->fade_out_len;
686
 
                if (cnt) {
687
 
                    short *samp = (dst - cnt);
688
 
                    const unsigned step = 0xFFFF / cnt;
689
 
                    unsigned scale = 0xFFFF - step;
690
 
 
691
 
                    for (; samp < dst; ++samp) {
692
 
                        (*samp) = (short)(((*samp) * scale) >> 16);
693
 
                        scale -= step;
694
 
                    }
695
 
                }
696
 
            }
697
 
 
698
 
            if (dst == end)
699
 
                break;
700
 
        }
701
 
 
702
 
        /* Add silence signal */
703
 
        cnt = off_samp + on_samp - tonegen->dig_samples;
704
 
        if (cnt > required)
705
 
            cnt = required;
706
 
        pjmedia_zero_samples(dst, cnt);
707
 
        dst += cnt;
708
 
        tonegen->dig_samples += cnt;
709
 
 
710
 
        /* Move to next digit if we're finished with this tone */
711
 
        if (tonegen->dig_samples >= on_samp + off_samp) {
712
 
            tonegen->cur_digit++;
713
 
            tonegen->dig_samples = 0;
714
 
 
715
 
            if (tonegen->cur_digit >= tonegen->count) {
716
 
                /* All digits have been played */
717
 
                if ((tonegen->options & PJMEDIA_TONEGEN_LOOP) ||
718
 
                    (tonegen->playback_options & PJMEDIA_TONEGEN_LOOP))
719
 
                {
720
 
                    tonegen->cur_digit = 0;
721
 
                } else {
722
 
                    break;
723
 
                }
724
 
            }
725
 
        }
726
 
    }
727
 
 
728
 
    if (dst < end)
729
 
        pjmedia_zero_samples(dst, end-dst);
730
 
 
731
 
    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
732
 
    frame->size = port->info.bytes_per_frame;
733
 
 
734
 
    TRACE_((THIS_FILE, "tonegen_get_frame(): frame created, level=%u",
735
 
            pjmedia_calc_avg_signal((pj_int16_t*)frame->buf, frame->size/2)));
736
 
 
737
 
    if (tonegen->cur_digit >= tonegen->count) {
738
 
        if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
739
 
        {
740
 
            /* Reset back to the first tone */
741
 
            tonegen->cur_digit = 0;
742
 
            tonegen->dig_samples = 0;
743
 
 
744
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
745
 
 
746
 
        } else {
747
 
            tonegen->count = 0;
748
 
            tonegen->cur_digit = 0;
749
 
 
750
 
            TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
751
 
        }
752
 
    }
753
 
 
754
 
on_return:
755
 
    pj_lock_release(tonegen->lock);
756
 
    return PJ_SUCCESS;
757
 
}
758
 
 
759
 
 
760
 
/*
761
 
 * Play tones.
762
 
 */
763
 
PJ_DEF(pj_status_t) pjmedia_tonegen_play( pjmedia_port *port,
764
 
                                          unsigned count,
765
 
                                          const pjmedia_tone_desc tones[],
766
 
                                          unsigned options)
767
 
{
768
 
    struct tonegen *tonegen = (struct tonegen*) port;
769
 
    unsigned i;
770
 
 
771
 
    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
772
 
                     count && tones, PJ_EINVAL);
773
 
 
774
 
    /* Don't put more than available buffer */
775
 
    PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
776
 
                     PJ_ETOOMANY);
777
 
 
778
 
    pj_lock_acquire(tonegen->lock);
779
 
 
780
 
    /* Set playback options */
781
 
    tonegen->playback_options = options;
782
 
    
783
 
    /* Copy digits */
784
 
    pj_memcpy(tonegen->digits + tonegen->count,
785
 
              tones, count * sizeof(pjmedia_tone_desc));
786
 
    
787
 
    /* Normalize volume, and check if we need to disable fading.
788
 
     * Disable fading if tone off time is zero. Application probably
789
 
     * wants to play this tone continuously (e.g. dial tone).
790
 
     */
791
 
    for (i=0; i<count; ++i) {
792
 
        pjmedia_tone_desc *t = &tonegen->digits[i+tonegen->count];
793
 
        if (t->volume == 0)
794
 
            t->volume = AMP;
795
 
        else if (t->volume < 0)
796
 
            t->volume = (short) -t->volume;
797
 
        /* Reset flags */
798
 
        t->flags = 0;
799
 
        if (t->off_msec != 0)
800
 
            t->flags |= PJMEDIA_TONE_ENABLE_FADE;
801
 
    }
802
 
 
803
 
    tonegen->count += count;
804
 
 
805
 
    pj_lock_release(tonegen->lock);
806
 
 
807
 
    return PJ_SUCCESS;
808
 
}
809
 
 
810
 
 
811
 
/*
812
 
 * Play digits.
813
 
 */
814
 
PJ_DEF(pj_status_t) pjmedia_tonegen_play_digits( pjmedia_port *port,
815
 
                                                 unsigned count,
816
 
                                                 const pjmedia_tone_digit digits[],
817
 
                                                 unsigned options)
818
 
{
819
 
    struct tonegen *tonegen = (struct tonegen*) port;
820
 
    pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
821
 
    const pjmedia_tone_digit_map *map;
822
 
    unsigned i;
823
 
 
824
 
    PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
825
 
                     count && digits, PJ_EINVAL);
826
 
    PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);
827
 
 
828
 
    pj_lock_acquire(tonegen->lock);
829
 
 
830
 
    map = tonegen->digit_map;
831
 
 
832
 
    for (i=0; i<count; ++i) {
833
 
        int d = pj_tolower(digits[i].digit);
834
 
        unsigned j;
835
 
 
836
 
        /* Translate ASCII digits with digitmap */
837
 
        for (j=0; j<map->count; ++j) {
838
 
            if (d == map->digits[j].digit)
839
 
                break;
840
 
        }
841
 
        if (j == map->count) {
842
 
            pj_lock_release(tonegen->lock);
843
 
            return PJMEDIA_RTP_EINDTMF;
844
 
        }
845
 
 
846
 
        tones[i].freq1 = map->digits[j].freq1;
847
 
        tones[i].freq2 = map->digits[j].freq2;
848
 
        tones[i].on_msec = digits[i].on_msec;
849
 
        tones[i].off_msec = digits[i].off_msec;
850
 
        tones[i].volume = digits[i].volume;
851
 
    }
852
 
 
853
 
    pj_lock_release(tonegen->lock);
854
 
 
855
 
    return pjmedia_tonegen_play(port, count, tones, options);
856
 
}
857
 
 
858
 
 
859
 
/*
860
 
 * Get the digit-map currently used by this tone generator.
861
 
 */
862
 
PJ_DEF(pj_status_t) pjmedia_tonegen_get_digit_map(pjmedia_port *port,
863
 
                                                  const pjmedia_tone_digit_map **m)
864
 
{
865
 
    struct tonegen *tonegen = (struct tonegen*) port;
866
 
    
867
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
868
 
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
869
 
 
870
 
    *m = tonegen->digit_map;
871
 
 
872
 
    return PJ_SUCCESS;
873
 
}
874
 
 
875
 
 
876
 
/*
877
 
 * Set digit map to be used by the tone generator.
878
 
 */
879
 
PJ_DEF(pj_status_t) pjmedia_tonegen_set_digit_map(pjmedia_port *port,
880
 
                                                  pjmedia_tone_digit_map *m)
881
 
{
882
 
    struct tonegen *tonegen = (struct tonegen*) port;
883
 
    
884
 
    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
885
 
    PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
886
 
 
887
 
    pj_lock_acquire(tonegen->lock);
888
 
 
889
 
    tonegen->digit_map = m;
890
 
 
891
 
    pj_lock_release(tonegen->lock);
892
 
 
893
 
    return PJ_SUCCESS;
894
 
}
895
 
 
896