audio_io_test_ec: apply command design pattern 16/261516/5 accepted/tizen/unified/20210923.133037 submit/tizen/20210923.034818
authorSeungbae Shin <seungbae.shin@samsung.com>
Tue, 20 Jul 2021 09:47:19 +0000 (18:47 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Tue, 20 Jul 2021 11:55:28 +0000 (20:55 +0900)
[Version] 0.5.42
[Issue Type] Refactoring

Change-Id: I2615757da7e51ecd338fbe5d39c64ee9f08ab762

packaging/capi-media-audio-io.spec
test/audio_io_test_ec.c [deleted file]
test/audio_io_test_ec.cpp [new file with mode: 0644]

index d954082..aaaa3b2 100644 (file)
@@ -1,6 +1,6 @@
 Name:           capi-media-audio-io
 Summary:        An Audio Input & Audio Output library in Tizen Native API
-Version:        0.5.41
+Version:        0.5.42
 Release:        0
 Group:          Multimedia/API
 License:        Apache-2.0
diff --git a/test/audio_io_test_ec.c b/test/audio_io_test_ec.c
deleted file mode 100644 (file)
index 1559cb3..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <time.h>
-#include <stdbool.h>
-
-#include <audio_io.h>
-#include <sound_manager.h>
-#include <sound_manager_internal.h>
-
-#ifndef TIZEN_FEATURE_TV_PROD
-static double _get_rand_double_range(double min, double max)
-{
-       double ret;
-       int r;
-
-       r = rand();
-       ret = (max / RAND_MAX) * r * (r & 0x1 ? 1 : -1);
-
-       return ret;
-}
-
-static void _white_noise_stream_write_cb(audio_out_h handle, size_t nbytes, void *user_data)
-{
-       int i;
-       short *ptr;
-       char *buffer;
-       double amp = 0.3 * 32767.0;
-
-       buffer = (char *)malloc(nbytes);
-       if (!buffer)
-               return;
-
-       ptr = (short *)buffer;
-       for (i = 0; i < nbytes; i += 2, ptr++)
-               ptr[0] = (short)(amp * _get_rand_double_range(-1.0, 1.0));
-
-       audio_out_write(handle, buffer, nbytes);
-
-       free(buffer);
-}
-
-int play_white_noise_async(audio_out_h *output)
-{
-       audio_out_h _output = NULL;
-       int ret;
-
-       srand(time(NULL));
-
-       ret = audio_out_create_new(48000, AUDIO_CHANNEL_STEREO, AUDIO_SAMPLE_TYPE_S16_LE, &_output);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to create audio out\n");
-               return -1;
-       }
-
-       ret = audio_out_set_stream_cb(_output, _white_noise_stream_write_cb, NULL);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to set stream callback\n");
-               goto fail;
-       }
-
-       ret = audio_out_prepare(_output);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to prepare \n");
-               goto fail;
-       }
-
-       *output = _output;
-
-       return 0;
-
-fail:
-       audio_out_destroy(_output);
-
-       return -1;
-}
-
-int stop_white_noise_async(audio_out_h output)
-{
-       int ret;
-
-       ret = audio_out_unprepare(output);
-       if (ret != AUDIO_IO_ERROR_NONE)
-               printf("failed to prepare\n");
-
-       ret = audio_out_destroy(output);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to destroy output\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-int capture_sound(char **buffer, int *length, int sec)
-{
-       int ret;
-       char *_buffer = NULL;
-       audio_in_h input = NULL;
-       int _length = 16000 * 1 * 2 * sec; // 16Khz, mono, S16LE
-
-       if (!buffer) {
-               printf("buffer is null\n");
-               return -1;
-       }
-
-       ret = audio_in_create(16000, AUDIO_CHANNEL_MONO, AUDIO_SAMPLE_TYPE_S16_LE, &input);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to create audio_input\n");
-               return -1;
-       }
-
-       ret = audio_in_prepare(input);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to prepare %x0x\n", ret);
-               goto fail;
-       }
-
-       _buffer = malloc(_length);
-       if (!_buffer) {
-               printf("_buffer is null\n");
-               goto fail;
-       }
-
-       ret = audio_in_read(input, _buffer, _length);
-       if (ret <= 0) {
-               printf("failed to read ret(0x%x), length(%d)\n", ret, _length);
-               goto fail;
-       }
-       ret = audio_in_unprepare(input);
-       if (ret != AUDIO_IO_ERROR_NONE) {
-               printf("failed to unprepare 0x%x", ret);
-               goto fail;
-       }
-
-       *buffer = _buffer;
-       *length = _length;
-
-       return 0;
-
-fail:
-       if (input)
-               audio_in_destroy(input);
-       if (buffer)
-               free(buffer);
-
-       return -1;
-}
-
-int enable_echo_cancellation(bool enable)
-{
-       int ret;
-
-       if (enable)
-               ret = sound_manager_start_aec();
-       else
-               ret = sound_manager_stop_aec();
-
-       if (ret != 0) {
-               printf("failed to %s echo cancellation. ret(0x%x)\n",
-                               enable ? "start" : "stop", ret);
-               return -1;
-       }
-
-       return 0;
-}
-
-int test_echo_cancellation(char **buffer, bool enable_ec, bool enable_ref, int time_sec)
-{
-       audio_out_h output = NULL;
-       char *_buffer = NULL;
-       int length;
-
-       if (enable_ec && enable_echo_cancellation(true))
-               goto exit;
-
-       if (enable_ref && play_white_noise_async(&output))
-               goto exit;
-
-       printf("Say something for %d seconds..  enable_ec(%s) enable_ref(%s)\n",
-                       time_sec,
-                       enable_ec ? "on" : "off",
-                       enable_ref? "on" : "off");
-
-       if (capture_sound(&_buffer, &length, time_sec))
-               goto exit;
-
-       if (output && stop_white_noise_async(output))
-               goto exit;
-
-       output = NULL;
-
-       if (enable_ec && enable_echo_cancellation(false))
-               goto exit;
-
-       *buffer = _buffer;
-
-       return length;
-
-exit:
-       if (output)
-               stop_white_noise_async(output);
-
-       if (enable_ec)
-               enable_echo_cancellation(false);
-
-       if (_buffer)
-               free(_buffer);
-
-       return -1;
-}
-
-int dump_to_file(const char *filename, char *buffer, int length)
-{
-       int fd, ret;
-
-       fd = open(filename, O_CREAT|O_TRUNC|O_RDWR, 0644);
-       if (fd < 0) {
-               printf("failed to open file\n");
-               return -1;
-       }
-
-       ret = write(fd, buffer, length);
-       if (ret < 0)
-               printf("failed to write\n");
-
-       close(fd);
-
-       return 0;
-}
-#endif
-
-int main(int argc, char **argv)
-{
-#ifndef TIZEN_FEATURE_TV_PROD
-       bool enable_ec;
-       bool enable_ref;
-       int time_sec;
-       char *filename;
-
-       char *buffer;
-       int size;
-
-       if (argc != 5) {
-               printf("- Usages :\n");
-               printf("- # audio_io_test_ec [filename] [on/off 0:1] [noise 0:1] [seconds]\n");
-               return -1;
-       }
-
-       filename  = argv[1];
-       enable_ec = !!atoi(argv[2]);
-       enable_ref = !!atoi(argv[3]);
-       time_sec = atoi(argv[4]);
-
-       size = test_echo_cancellation(&buffer, enable_ec, enable_ref, time_sec);
-       if (size <= 0) {
-               printf("failed to test aec\n");
-               return -1;
-       }
-
-       if (dump_to_file(filename, buffer, size))
-               printf("failed to save file %s\n", filename);
-
-       if (buffer)
-               free(buffer);
-#else
-       printf("not supported yet\n");
-#endif
-
-       return 0;
-}
-
diff --git a/test/audio_io_test_ec.cpp b/test/audio_io_test_ec.cpp
new file mode 100644 (file)
index 0000000..88f7d8b
--- /dev/null
@@ -0,0 +1,360 @@
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <map>
+#include <memory>
+#include <iostream>
+
+#include <audio_io.h>
+#include <sound_manager.h>
+#include <sound_manager_internal.h>
+
+#ifndef TIZEN_FEATURE_TV_PROD
+
+enum Receiver
+{
+       ECHO_CANCELLER = 0,
+       NOISE_GENERATOR,
+};
+
+class Command
+{
+public:
+       virtual void execute() const = 0;
+};
+
+class EchoCanceller
+{
+public:
+       EchoCanceller() = default;
+       virtual ~EchoCanceller() = default;
+
+       void on() {
+               int ret = sound_manager_start_aec();
+               if (ret != 0)
+                       std::cerr << "failed to start echo cancellation, " << ret << std::endl;
+               else
+                       std::cout << "[ON]  Echo Canceller" << std::endl;
+       }
+       void off() {
+               int ret = sound_manager_stop_aec();
+               if (ret != 0)
+                       std::cerr << "failed to stop echo cancellation, " << ret << std::endl;
+               else
+                       std::cout << "[OFF] Echo Canceller" << std::endl;
+       }
+};
+
+class NoiseGenerator
+{
+public:
+       NoiseGenerator() = default;
+       virtual ~NoiseGenerator() = default;
+
+       void on() {
+               std::cout << "[ON]  Noise Generator" << std::endl;
+               playWhiteNoise();
+       }
+       void off() {
+               std::cout << "[OFF] Noise Generator" << std::endl;
+               stopWhiteNoise();
+       }
+
+private:
+       void playWhiteNoise();
+       void stopWhiteNoise();
+
+       static void _streamWriteCb(audio_out_h handle, size_t nbytes, void *user_data);
+       static double _getRandDoubleRange(double min, double max);
+
+       audio_out_h output{};
+};
+
+void NoiseGenerator::playWhiteNoise()
+{
+       audio_out_h _output = nullptr;
+
+       srand(time(NULL));
+
+       int ret = audio_out_create_new(48000, AUDIO_CHANNEL_STEREO, AUDIO_SAMPLE_TYPE_S16_LE, &_output);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to create audio out" << std::endl;
+               return;
+       }
+
+       ret = audio_out_set_stream_cb(_output, _streamWriteCb, NULL);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to set stream callback" << std::endl;
+               audio_out_destroy(_output);
+               return;
+       }
+
+       ret = audio_out_prepare(_output);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to prepare " << std::endl;
+               audio_out_destroy(_output);
+               return;
+       }
+
+       output = _output;
+}
+
+void NoiseGenerator::stopWhiteNoise()
+{
+       if (!output)
+               return;
+
+       int ret = audio_out_unprepare(output);
+       if (ret != AUDIO_IO_ERROR_NONE)
+               std::cerr << "failed to prepare" << std::endl;
+
+       ret = audio_out_destroy(output);
+       if (ret != AUDIO_IO_ERROR_NONE)
+               std::cerr << "failed to destroy output" << std::endl;
+
+       output = nullptr;
+}
+
+double  NoiseGenerator::_getRandDoubleRange(double min, double max)
+{
+       static unsigned int seedp;
+       int r = rand_r(&seedp);
+       return (max / RAND_MAX) * r * (r & 0x1 ? 1 : -1);
+}
+
+void NoiseGenerator::_streamWriteCb(audio_out_h handle, size_t nbytes, void *user_data)
+{
+       constexpr double amp = 0.3 * 32767.0;
+
+       auto buffer = static_cast<short *>(malloc(nbytes));
+       if (!buffer)
+               return;
+
+       auto ptr = buffer;
+       for (size_t i = 0; i < nbytes; i += 2, ptr++)
+               ptr[0] = (short)(amp * _getRandDoubleRange(-1.0, 1.0));
+
+       audio_out_write(handle, static_cast<void*>(buffer), nbytes);
+
+       free(buffer);
+}
+
+class EchoCancellerOnCommand : public Command
+{
+public:
+       explicit EchoCancellerOnCommand(std::shared_ptr<EchoCanceller>& ec) : ec(ec) {}
+       virtual ~EchoCancellerOnCommand() = default;
+       void execute() const override { ec->on(); }
+
+private:
+       std::shared_ptr<EchoCanceller> ec;
+};
+
+class EchoCancellerOffCommand : public Command
+{
+public:
+       explicit EchoCancellerOffCommand(std::shared_ptr<EchoCanceller>& ec) : ec(ec) {}
+       virtual ~EchoCancellerOffCommand() = default;
+       void execute() const override { ec->off(); }
+
+private:
+       std::shared_ptr<EchoCanceller> ec;
+};
+
+class NoiseGeneratorOnCommand : public Command
+{
+public:
+       explicit NoiseGeneratorOnCommand(std::shared_ptr<NoiseGenerator>& ng) : ng(ng) {}
+       virtual ~NoiseGeneratorOnCommand() = default;
+       void execute() const override { ng->on(); }
+
+private:
+       std::shared_ptr<NoiseGenerator> ng;
+};
+
+class NoiseGeneratorOffCommand : public Command
+{
+public:
+       explicit NoiseGeneratorOffCommand(std::shared_ptr<NoiseGenerator>& ng) : ng(ng) {}
+       virtual ~NoiseGeneratorOffCommand() = default;
+       void execute() const override { ng->off(); }
+
+private:
+       std::shared_ptr<NoiseGenerator> ng;
+};
+
+
+class RemoteControl
+{
+public:
+       RemoteControl() = default;
+
+       void addCommand(Receiver id, std::pair<std::shared_ptr<Command>, std::shared_ptr<Command>> Commands) {
+               commands.insert({id, Commands});
+       }
+
+       void onButtonPressed(Receiver id) {
+               if (commands.find(id) != commands.end())
+                       commands[id].first->execute();
+       }
+
+       void offButtonPressed(Receiver id) {
+               if (commands.find(id) != commands.end())
+                       commands[id].second->execute();
+       }
+
+private:
+       std::map<Receiver, std::pair<std::shared_ptr<Command>, std::shared_ptr<Command>>> commands{};
+};
+
+int capture_sound(char **buffer, int *length, int sec)
+{
+       int ret;
+       char *_buffer = NULL;
+       audio_in_h input = NULL;
+       int _length = 16000 * 1 * 2 * sec; // 16Khz, mono, S16LE
+
+       if (!buffer) {
+               std::cout << "buffer is null" << std::endl;
+               return -1;
+       }
+
+       ret = audio_in_create(16000, AUDIO_CHANNEL_MONO, AUDIO_SAMPLE_TYPE_S16_LE, &input);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to create audio_input" << std::endl;
+               return -1;
+       }
+
+       ret = audio_in_prepare(input);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to prepare, " << ret << std::endl;
+               goto fail;
+       }
+
+       _buffer = static_cast<char *>(malloc(_length));
+       if (!_buffer) {
+               std::cerr << "_buffer is null" << std::endl;
+               goto fail;
+       }
+
+       ret = audio_in_read(input, _buffer, _length);
+       if (ret <= 0) {
+               std::cerr << "failed to read, " << ret << ", " << _length << std::endl;
+               goto fail;
+       }
+       ret = audio_in_unprepare(input);
+       if (ret != AUDIO_IO_ERROR_NONE) {
+               std::cerr << "failed to unprepare, " << ret << std::endl;
+               goto fail;
+       }
+
+       *buffer = _buffer;
+       *length = _length;
+
+       return 0;
+
+fail:
+       if (input)
+               audio_in_destroy(input);
+       if (buffer)
+               free(buffer);
+
+       return -1;
+}
+
+int test_echo_cancellation(char **buffer, bool enable_ec, bool enable_ref, int time_sec)
+{
+       int ret;
+       char *_buffer = NULL;
+       int length = -1;
+
+       auto ec = std::make_shared<EchoCanceller>();
+       auto ng = std::make_shared<NoiseGenerator>();
+
+       RemoteControl control;
+       control.addCommand(Receiver::ECHO_CANCELLER,
+                                          { std::make_shared<EchoCancellerOnCommand>(ec),
+                                                std::make_shared<EchoCancellerOffCommand>(ec) });
+       control.addCommand(Receiver::NOISE_GENERATOR,
+                                          { std::make_shared<NoiseGeneratorOnCommand>(ng),
+                                                std::make_shared<NoiseGeneratorOffCommand>(ng) });
+
+       if (enable_ec)
+               control.onButtonPressed(Receiver::ECHO_CANCELLER);
+       if (enable_ref)
+               control.onButtonPressed(Receiver::NOISE_GENERATOR);
+
+       std::cout << "Say something for " << time_sec << " seconds..  ec " << enable_ec << ", ref " << enable_ref << std::endl;
+
+       ret = capture_sound(&_buffer, &length, time_sec);
+
+       if (enable_ref)
+               control.offButtonPressed(Receiver::NOISE_GENERATOR);
+       if (enable_ec)
+               control.offButtonPressed(Receiver::ECHO_CANCELLER);
+
+       if (ret == 0)
+               *buffer = _buffer;
+       else
+               free(_buffer);
+
+       return length;
+}
+
+int dump_to_file(const char *filename, char *buffer, int length)
+{
+       int fd = open(filename, O_CREAT|O_TRUNC|O_RDWR, 0644);
+       if (fd < 0) {
+               std::cerr << "failed to open file" << std::endl;
+               return -1;
+       }
+
+       ssize_t ret = write(fd, buffer, length);
+       if (ret < 0)
+               std::cerr << "failed to write" << std::endl;
+
+       close(fd);
+
+       return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+#ifndef TIZEN_FEATURE_TV_PROD
+       bool enable_ec;
+       bool enable_ref;
+       int time_sec;
+       char *filename;
+
+       char *buffer = NULL;
+       int size;
+
+       if (argc != 5) {
+               std::cout << "- Usages :" << std::endl;
+               std::cout << "- # audio_io_test_ec [filename] [on/off 0:1] [noise 0:1] [seconds]" << std::endl;
+               return -1;
+       }
+
+       filename  = argv[1];
+       enable_ec = !!atoi(argv[2]);
+       enable_ref = !!atoi(argv[3]);
+       time_sec = atoi(argv[4]);
+
+       size = test_echo_cancellation(&buffer, enable_ec, enable_ref, time_sec);
+       if (size <= 0) {
+               std::cerr << "failed to test aec" << std::endl;
+               return -1;
+       }
+
+       if (dump_to_file(filename, buffer, size))
+               std::cerr << "failed to save file, " << filename << std::endl;
+       if (buffer)
+               free(buffer);
+#else
+       std::cout << "not supported yet" << std::endl;
+#endif
+
+       return 0;
+}
\ No newline at end of file