88f7d8b355226cb15489b55362a6d95e3ce3e991
[platform/core/api/audio-io.git] / test / audio_io_test_ec.cpp
1 #include <unistd.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4
5 #include <map>
6 #include <memory>
7 #include <iostream>
8
9 #include <audio_io.h>
10 #include <sound_manager.h>
11 #include <sound_manager_internal.h>
12
13 #ifndef TIZEN_FEATURE_TV_PROD
14
15 enum Receiver
16 {
17         ECHO_CANCELLER = 0,
18         NOISE_GENERATOR,
19 };
20
21 class Command
22 {
23 public:
24         virtual void execute() const = 0;
25 };
26
27 class EchoCanceller
28 {
29 public:
30         EchoCanceller() = default;
31         virtual ~EchoCanceller() = default;
32
33         void on() {
34                 int ret = sound_manager_start_aec();
35                 if (ret != 0)
36                         std::cerr << "failed to start echo cancellation, " << ret << std::endl;
37                 else
38                         std::cout << "[ON]  Echo Canceller" << std::endl;
39         }
40         void off() {
41                 int ret = sound_manager_stop_aec();
42                 if (ret != 0)
43                         std::cerr << "failed to stop echo cancellation, " << ret << std::endl;
44                 else
45                         std::cout << "[OFF] Echo Canceller" << std::endl;
46         }
47 };
48
49 class NoiseGenerator
50 {
51 public:
52         NoiseGenerator() = default;
53         virtual ~NoiseGenerator() = default;
54
55         void on() {
56                 std::cout << "[ON]  Noise Generator" << std::endl;
57                 playWhiteNoise();
58         }
59         void off() {
60                 std::cout << "[OFF] Noise Generator" << std::endl;
61                 stopWhiteNoise();
62         }
63
64 private:
65         void playWhiteNoise();
66         void stopWhiteNoise();
67
68         static void _streamWriteCb(audio_out_h handle, size_t nbytes, void *user_data);
69         static double _getRandDoubleRange(double min, double max);
70
71         audio_out_h output{};
72 };
73
74 void NoiseGenerator::playWhiteNoise()
75 {
76         audio_out_h _output = nullptr;
77
78         srand(time(NULL));
79
80         int ret = audio_out_create_new(48000, AUDIO_CHANNEL_STEREO, AUDIO_SAMPLE_TYPE_S16_LE, &_output);
81         if (ret != AUDIO_IO_ERROR_NONE) {
82                 std::cerr << "failed to create audio out" << std::endl;
83                 return;
84         }
85
86         ret = audio_out_set_stream_cb(_output, _streamWriteCb, NULL);
87         if (ret != AUDIO_IO_ERROR_NONE) {
88                 std::cerr << "failed to set stream callback" << std::endl;
89                 audio_out_destroy(_output);
90                 return;
91         }
92
93         ret = audio_out_prepare(_output);
94         if (ret != AUDIO_IO_ERROR_NONE) {
95                 std::cerr << "failed to prepare " << std::endl;
96                 audio_out_destroy(_output);
97                 return;
98         }
99
100         output = _output;
101 }
102
103 void NoiseGenerator::stopWhiteNoise()
104 {
105         if (!output)
106                 return;
107
108         int ret = audio_out_unprepare(output);
109         if (ret != AUDIO_IO_ERROR_NONE)
110                 std::cerr << "failed to prepare" << std::endl;
111
112         ret = audio_out_destroy(output);
113         if (ret != AUDIO_IO_ERROR_NONE)
114                 std::cerr << "failed to destroy output" << std::endl;
115
116         output = nullptr;
117 }
118
119 double  NoiseGenerator::_getRandDoubleRange(double min, double max)
120 {
121         static unsigned int seedp;
122         int r = rand_r(&seedp);
123         return (max / RAND_MAX) * r * (r & 0x1 ? 1 : -1);
124 }
125
126 void NoiseGenerator::_streamWriteCb(audio_out_h handle, size_t nbytes, void *user_data)
127 {
128         constexpr double amp = 0.3 * 32767.0;
129
130         auto buffer = static_cast<short *>(malloc(nbytes));
131         if (!buffer)
132                 return;
133
134         auto ptr = buffer;
135         for (size_t i = 0; i < nbytes; i += 2, ptr++)
136                 ptr[0] = (short)(amp * _getRandDoubleRange(-1.0, 1.0));
137
138         audio_out_write(handle, static_cast<void*>(buffer), nbytes);
139
140         free(buffer);
141 }
142
143 class EchoCancellerOnCommand : public Command
144 {
145 public:
146         explicit EchoCancellerOnCommand(std::shared_ptr<EchoCanceller>& ec) : ec(ec) {}
147         virtual ~EchoCancellerOnCommand() = default;
148         void execute() const override { ec->on(); }
149
150 private:
151         std::shared_ptr<EchoCanceller> ec;
152 };
153
154 class EchoCancellerOffCommand : public Command
155 {
156 public:
157         explicit EchoCancellerOffCommand(std::shared_ptr<EchoCanceller>& ec) : ec(ec) {}
158         virtual ~EchoCancellerOffCommand() = default;
159         void execute() const override { ec->off(); }
160
161 private:
162         std::shared_ptr<EchoCanceller> ec;
163 };
164
165 class NoiseGeneratorOnCommand : public Command
166 {
167 public:
168         explicit NoiseGeneratorOnCommand(std::shared_ptr<NoiseGenerator>& ng) : ng(ng) {}
169         virtual ~NoiseGeneratorOnCommand() = default;
170         void execute() const override { ng->on(); }
171
172 private:
173         std::shared_ptr<NoiseGenerator> ng;
174 };
175
176 class NoiseGeneratorOffCommand : public Command
177 {
178 public:
179         explicit NoiseGeneratorOffCommand(std::shared_ptr<NoiseGenerator>& ng) : ng(ng) {}
180         virtual ~NoiseGeneratorOffCommand() = default;
181         void execute() const override { ng->off(); }
182
183 private:
184         std::shared_ptr<NoiseGenerator> ng;
185 };
186
187
188 class RemoteControl
189 {
190 public:
191         RemoteControl() = default;
192
193         void addCommand(Receiver id, std::pair<std::shared_ptr<Command>, std::shared_ptr<Command>> Commands) {
194                 commands.insert({id, Commands});
195         }
196
197         void onButtonPressed(Receiver id) {
198                 if (commands.find(id) != commands.end())
199                         commands[id].first->execute();
200         }
201
202         void offButtonPressed(Receiver id) {
203                 if (commands.find(id) != commands.end())
204                         commands[id].second->execute();
205         }
206
207 private:
208         std::map<Receiver, std::pair<std::shared_ptr<Command>, std::shared_ptr<Command>>> commands{};
209 };
210
211 int capture_sound(char **buffer, int *length, int sec)
212 {
213         int ret;
214         char *_buffer = NULL;
215         audio_in_h input = NULL;
216         int _length = 16000 * 1 * 2 * sec; // 16Khz, mono, S16LE
217
218         if (!buffer) {
219                 std::cout << "buffer is null" << std::endl;
220                 return -1;
221         }
222
223         ret = audio_in_create(16000, AUDIO_CHANNEL_MONO, AUDIO_SAMPLE_TYPE_S16_LE, &input);
224         if (ret != AUDIO_IO_ERROR_NONE) {
225                 std::cerr << "failed to create audio_input" << std::endl;
226                 return -1;
227         }
228
229         ret = audio_in_prepare(input);
230         if (ret != AUDIO_IO_ERROR_NONE) {
231                 std::cerr << "failed to prepare, " << ret << std::endl;
232                 goto fail;
233         }
234
235         _buffer = static_cast<char *>(malloc(_length));
236         if (!_buffer) {
237                 std::cerr << "_buffer is null" << std::endl;
238                 goto fail;
239         }
240
241         ret = audio_in_read(input, _buffer, _length);
242         if (ret <= 0) {
243                 std::cerr << "failed to read, " << ret << ", " << _length << std::endl;
244                 goto fail;
245         }
246         ret = audio_in_unprepare(input);
247         if (ret != AUDIO_IO_ERROR_NONE) {
248                 std::cerr << "failed to unprepare, " << ret << std::endl;
249                 goto fail;
250         }
251
252         *buffer = _buffer;
253         *length = _length;
254
255         return 0;
256
257 fail:
258         if (input)
259                 audio_in_destroy(input);
260         if (buffer)
261                 free(buffer);
262
263         return -1;
264 }
265
266 int test_echo_cancellation(char **buffer, bool enable_ec, bool enable_ref, int time_sec)
267 {
268         int ret;
269         char *_buffer = NULL;
270         int length = -1;
271
272         auto ec = std::make_shared<EchoCanceller>();
273         auto ng = std::make_shared<NoiseGenerator>();
274
275         RemoteControl control;
276         control.addCommand(Receiver::ECHO_CANCELLER,
277                                            { std::make_shared<EchoCancellerOnCommand>(ec),
278                                                  std::make_shared<EchoCancellerOffCommand>(ec) });
279         control.addCommand(Receiver::NOISE_GENERATOR,
280                                            { std::make_shared<NoiseGeneratorOnCommand>(ng),
281                                                  std::make_shared<NoiseGeneratorOffCommand>(ng) });
282
283         if (enable_ec)
284                 control.onButtonPressed(Receiver::ECHO_CANCELLER);
285         if (enable_ref)
286                 control.onButtonPressed(Receiver::NOISE_GENERATOR);
287
288         std::cout << "Say something for " << time_sec << " seconds..  ec " << enable_ec << ", ref " << enable_ref << std::endl;
289
290         ret = capture_sound(&_buffer, &length, time_sec);
291
292         if (enable_ref)
293                 control.offButtonPressed(Receiver::NOISE_GENERATOR);
294         if (enable_ec)
295                 control.offButtonPressed(Receiver::ECHO_CANCELLER);
296
297         if (ret == 0)
298                 *buffer = _buffer;
299         else
300                 free(_buffer);
301
302         return length;
303 }
304
305 int dump_to_file(const char *filename, char *buffer, int length)
306 {
307         int fd = open(filename, O_CREAT|O_TRUNC|O_RDWR, 0644);
308         if (fd < 0) {
309                 std::cerr << "failed to open file" << std::endl;
310                 return -1;
311         }
312
313         ssize_t ret = write(fd, buffer, length);
314         if (ret < 0)
315                 std::cerr << "failed to write" << std::endl;
316
317         close(fd);
318
319         return 0;
320 }
321 #endif
322
323 int main(int argc, char **argv)
324 {
325 #ifndef TIZEN_FEATURE_TV_PROD
326         bool enable_ec;
327         bool enable_ref;
328         int time_sec;
329         char *filename;
330
331         char *buffer = NULL;
332         int size;
333
334         if (argc != 5) {
335                 std::cout << "- Usages :" << std::endl;
336                 std::cout << "- # audio_io_test_ec [filename] [on/off 0:1] [noise 0:1] [seconds]" << std::endl;
337                 return -1;
338         }
339
340         filename  = argv[1];
341         enable_ec = !!atoi(argv[2]);
342         enable_ref = !!atoi(argv[3]);
343         time_sec = atoi(argv[4]);
344
345         size = test_echo_cancellation(&buffer, enable_ec, enable_ref, time_sec);
346         if (size <= 0) {
347                 std::cerr << "failed to test aec" << std::endl;
348                 return -1;
349         }
350
351         if (dump_to_file(filename, buffer, size))
352                 std::cerr << "failed to save file, " << filename << std::endl;
353         if (buffer)
354                 free(buffer);
355 #else
356         std::cout << "not supported yet" << std::endl;
357 #endif
358
359         return 0;
360 }