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 32 : DTMFGenerator::DTMFGenerator(unsigned int sampleRate, AVSampleFormat sampleFormat)
57 32 : : state()
58 32 : , sampleRate_(sampleRate)
59 32 : , tone_("", sampleRate, sampleFormat)
60 : {
61 32 : state.offset = 0;
62 32 : state.sample = 0;
63 :
64 544 : for (int i = 0; i < NUM_TONES; i++)
65 512 : toneBuffers_[i] = fillToneBuffer(i);
66 32 : }
67 :
68 32 : DTMFGenerator::~DTMFGenerator() {}
69 :
70 : void
71 0 : DTMFGenerator::getSamples(AVFrame* frame, unsigned char code)
72 : {
73 0 : code = toupper(code);
74 :
75 0 : if (code >= '0' and code <= '9')
76 0 : state.sample = toneBuffers_[code - '0'].get();
77 0 : else if (code >= 'A' and code <= 'D')
78 0 : state.sample = toneBuffers_[code - 'A' + 10].get();
79 : else {
80 0 : switch (code) {
81 0 : case '*':
82 0 : state.sample = toneBuffers_[NUM_TONES - 2].get();
83 0 : break;
84 :
85 0 : case '#':
86 0 : state.sample = toneBuffers_[NUM_TONES - 1].get();
87 0 : break;
88 :
89 0 : default:
90 0 : throw DTMFException("Invalid code");
91 : break;
92 : }
93 : }
94 :
95 0 : av_samples_copy(frame->data,
96 0 : state.sample->data,
97 : 0,
98 0 : state.offset,
99 : frame->nb_samples,
100 : frame->ch_layout.nb_channels,
101 0 : (AVSampleFormat) frame->format);
102 0 : state.offset = frame->nb_samples % sampleRate_;
103 0 : }
104 :
105 : /*
106 : * Get next n samples (continues where previous call to
107 : * genSample or genNextSamples stopped
108 : */
109 : void
110 0 : DTMFGenerator::getNextSamples(AVFrame* frame)
111 : {
112 0 : if (state.sample == 0)
113 0 : throw DTMFException("DTMF generator not initialized");
114 :
115 0 : av_samples_copy(frame->data,
116 0 : state.sample->data,
117 : 0,
118 0 : state.offset,
119 : frame->nb_samples,
120 : frame->ch_layout.nb_channels,
121 0 : (AVSampleFormat) frame->format);
122 0 : state.offset = (state.offset + frame->nb_samples) % sampleRate_;
123 0 : }
124 :
125 : libjami::FrameBuffer
126 512 : DTMFGenerator::fillToneBuffer(unsigned index)
127 : {
128 512 : assert(index < NUM_TONES);
129 512 : libjami::FrameBuffer ptr(av_frame_alloc());
130 512 : ptr->nb_samples = sampleRate_;
131 512 : ptr->format = tone_.getFormat().sampleFormat;
132 512 : ptr->sample_rate = sampleRate_;
133 512 : ptr->channel_layout = AV_CH_LAYOUT_MONO;
134 512 : av_channel_layout_from_mask(&ptr->ch_layout, AV_CH_LAYOUT_MONO);
135 512 : av_frame_get_buffer(ptr.get(), 0);
136 512 : tone_.genSin(ptr.get(), 0, ptr->nb_samples, TONES[index].higher, TONES[index].lower);
137 512 : return ptr;
138 0 : }
139 :
140 : } // namespace jami
|