blob: ea7c7bf2b25c8afef6f180455b75592c18f20663 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
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
228struct gen_state
229{
230 struct gen tone1;
231 struct gen tone2;
232 pj_bool_t has_tone2;
233};
234
235
236static 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
245static 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
269static 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
281static 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
310static 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
323static 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
346enum flags
347{
348 PJMEDIA_TONE_INITIALIZED = 1,
349 PJMEDIA_TONE_ENABLE_FADE = 2
350};
351
352struct 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 */
380static 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
404static pj_status_t tonegen_get_frame(pjmedia_port *this_port,
405 pjmedia_frame *frame);
406static 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 */
413PJ_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
470PJ_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 */
487PJ_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 */
498PJ_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 */
518PJ_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 */
538static 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 */
556static 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 = (unsigned)(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, (unsigned)(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
756on_return:
757 pj_lock_release(tonegen->lock);
758 return PJ_SUCCESS;
759}
760
761
762/*
763 * Play tones.
764 */
765PJ_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 */
816PJ_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 */
864PJ_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 */
881PJ_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}
897
898