Line data Source code
1 : /*
2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 : #include "dtmfgenerator.h"
18 : #include "libav_deps.h"
19 :
20 : #include <cmath>
21 : #include <cassert>
22 :
23 : namespace jami {
24 :
25 : /** Struct to handle a DTMF */
26 : struct DTMFTone
27 : {
28 : unsigned char code; /** Code of the tone */
29 : unsigned lower; /** Lower frequency */
30 : unsigned higher; /** Higher frequency */
31 : };
32 :
33 : /*
34 : * Tone frequencies
35 : */
36 : constexpr DTMFTone TONES[] = {{'0', 941, 1336},
37 : {'1', 697, 1209},
38 : {'2', 697, 1336},
39 : {'3', 697, 1477},
40 : {'4', 770, 1209},
41 : {'5', 770, 1336},
42 : {'6', 770, 1477},
43 : {'7', 852, 1209},
44 : {'8', 852, 1336},
45 : {'9', 852, 1477},
46 : {'A', 697, 1633},
47 : {'B', 770, 1633},
48 : {'C', 852, 1633},
49 : {'D', 941, 1633},
50 : {'*', 941, 1209},
51 : {'#', 941, 1477}};
52 :
53 : /*
54 : * Initialize the generator
55 : */
56 31 : DTMFGenerator::DTMFGenerator(unsigned int sampleRate, AVSampleFormat sampleFormat)
57 31 : : state()
58 31 : , sampleRate_(sampleRate)
59 31 : , tone_("", sampleRate, sampleFormat)
60 : {
61 31 : state.offset = 0;
62 31 : state.sample = 0;
63 :
64 527 : for (int i = 0; i < NUM_TONES; i++)
65 496 : toneBuffers_[i] = fillToneBuffer(i);
66 31 : }
67 :
68 31 : DTMFGenerator::~DTMFGenerator() {}
69 :
70 : using std::vector;
71 :
72 : void
73 0 : DTMFGenerator::getSamples(AVFrame* frame, unsigned char code)
74 : {
75 0 : code = toupper(code);
76 :
77 0 : if (code >= '0' and code <= '9')
78 0 : state.sample = toneBuffers_[code - '0'].get();
79 0 : else if (code >= 'A' and code <= 'D')
80 0 : state.sample = toneBuffers_[code - 'A' + 10].get();
81 : else {
82 0 : switch (code) {
83 0 : case '*':
84 0 : state.sample = toneBuffers_[NUM_TONES - 2].get();
85 0 : break;
86 :
87 0 : case '#':
88 0 : state.sample = toneBuffers_[NUM_TONES - 1].get();
89 0 : break;
90 :
91 0 : default:
92 0 : throw DTMFException("Invalid code");
93 : break;
94 : }
95 : }
96 :
97 0 : av_samples_copy(frame->data,
98 0 : state.sample->data,
99 : 0,
100 0 : state.offset,
101 : frame->nb_samples,
102 : frame->ch_layout.nb_channels,
103 0 : (AVSampleFormat) frame->format);
104 0 : state.offset = frame->nb_samples % sampleRate_;
105 0 : }
106 :
107 : /*
108 : * Get next n samples (continues where previous call to
109 : * genSample or genNextSamples stopped
110 : */
111 : void
112 0 : DTMFGenerator::getNextSamples(AVFrame* frame)
113 : {
114 0 : if (state.sample == 0)
115 0 : throw DTMFException("DTMF generator not initialized");
116 :
117 0 : av_samples_copy(frame->data,
118 0 : state.sample->data,
119 : 0,
120 0 : state.offset,
121 : frame->nb_samples,
122 : frame->ch_layout.nb_channels,
123 0 : (AVSampleFormat) frame->format);
124 0 : state.offset = (state.offset + frame->nb_samples) % sampleRate_;
125 0 : }
126 :
127 : libjami::FrameBuffer
128 496 : DTMFGenerator::fillToneBuffer(unsigned index)
129 : {
130 496 : assert(index < NUM_TONES);
131 496 : libjami::FrameBuffer ptr(av_frame_alloc());
132 496 : ptr->nb_samples = sampleRate_;
133 496 : ptr->format = tone_.getFormat().sampleFormat;
134 496 : ptr->sample_rate = sampleRate_;
135 496 : ptr->channel_layout = AV_CH_LAYOUT_MONO;
136 496 : av_channel_layout_from_mask(&ptr->ch_layout, AV_CH_LAYOUT_MONO);
137 496 : av_frame_get_buffer(ptr.get(), 0);
138 496 : tone_.genSin(ptr.get(), 0, ptr->nb_samples, TONES[index].higher, TONES[index].lower);
139 496 : return ptr;
140 0 : }
141 :
142 : } // namespace jami
|