Initial upload version 0.0.1 61/293161/13 accepted/tizen/unified/20230615.060034
authorJaechul Lee <jcsing.lee@samsung.com>
Mon, 22 May 2023 04:16:34 +0000 (13:16 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Wed, 14 Jun 2023 06:41:12 +0000 (15:41 +0900)
Change-Id: Ia482873e164f17d9471f919f4e83389b407a3ba2
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
30 files changed:
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
include/audio_effect.h [new file with mode: 0644]
include/audio_effect_interface.h [new file with mode: 0644]
include/audio_effect_log.h [new file with mode: 0644]
include/audio_effect_util.h [new file with mode: 0644]
libaudio-effect.manifest [new file with mode: 0644]
meson.build [new file with mode: 0644]
meson_options.txt [new file with mode: 0644]
packaging/libaudio-effect.spec [new file with mode: 0644]
src/audio_effect.c [new file with mode: 0644]
src/audio_effect_interface.c [new file with mode: 0644]
src/audio_effect_util.c [new file with mode: 0644]
src/plugin_aec_refcopy.c [new file with mode: 0644]
src/plugin_aec_speex.c [new file with mode: 0644]
src/plugin_aec_webrtc.cpp [new file with mode: 0644]
src/plugin_agc_speex.c [new file with mode: 0644]
src/plugin_amplify.c [new file with mode: 0644]
src/plugin_ns_rnnoise.c [new file with mode: 0644]
test/aec_refcopy_test.c [new file with mode: 0644]
test/aec_speex_test.c [new file with mode: 0644]
test/aec_webrtc_test.c [new file with mode: 0644]
test/amplify_test.c [new file with mode: 0644]
test/meson.build [new file with mode: 0644]
test/ns_rnnoise_test.c [new file with mode: 0644]
test/resources/airport_48k.raw [new file with mode: 0644]
test/resources/obama.raw [new file with mode: 0644]
test/resources/rec.raw [new file with mode: 0644]
test/resources/rec_refcopy_5ch.raw [new file with mode: 0644]
test/resources/ref.raw [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..bbe9d02
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,206 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+\r
+\r
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..d9344d1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# libaudio-effect
+Additional audio pre-process methods.
+
+## How to build
+ * local : meson build --reconfigure [-Dtestsuite=enabled]  && ninja -C build clean && ninja -C build/
+   e.g) meson build --reconfigure -Db_sanitize=address -Db_coverage=true -Dtestsuite=enabled -Damplify=enabled -Dspeex-agc=enabled -Dns-rnnoise=enabled -Daec-refcopy=enabled -Daec-speex=enabled -Daec-webrtc=enabled && ninja -C build clean && ninja -C build/
+ * GBS : gbs build -A aarch64 --include-all
+
+## How to test
+ * cd build/test
+ * export LD_LIBRARY_PATH=../
+ * ./aec_refcopy_test
diff --git a/include/audio_effect.h b/include/audio_effect.h
new file mode 100644 (file)
index 0000000..b7836d1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __AUDIO_EFFECT_H__
+#define __AUDIO_EFFECT_H__
+
+#include <stddef.h>
+
+typedef struct audio_effect_interface audio_effect_interface_s;
+typedef enum {
+       /* Acoustic Echo Cancellation */
+       AUDIO_EFFECT_TYPE_AEC_SPEEX, /* aec from speexdsp */
+       AUDIO_EFFECT_TYPE_AEC_WEBRTC, /* aec from webrtc-audio-processing */
+       AUDIO_EFFECT_TYPE_AEC_REFCOPY, /* synthesis reference source into recording source */
+
+       /* Noise Suppression */
+       AUDIO_EFFECT_TYPE_NS_PSE, /* SAIC NS solution */
+       AUDIO_EFFECT_TYPE_NS_RNNOISE, /* RNNoise */
+
+       /* Template */
+       AUDIO_EFFECT_TYPE_AMPLIFY,
+
+       /* Experiment */
+       AUDIO_EFFECT_TYPE_AGC_SPEEX,
+       AUDIO_EFFECT_TYPE_MAX,
+} audio_effect_type_e;
+
+typedef enum {
+       AUDIO_EFFECT_FORMAT_S8,
+       AUDIO_EFFECT_FORMAT_S16,
+       AUDIO_EFFECT_FORMAT_S24,
+       AUDIO_EFFECT_FORMAT_S32,
+       AUDIO_EFFECT_FORMAT_FLOAT,
+       AUDIO_EFFECT_FORMAT_MAX,
+} audio_effect_format_e;
+
+typedef struct audio_effect {
+       void *priv;
+       audio_effect_interface_s *intf;
+       size_t request_framesize;
+} audio_effect_s;
+
+audio_effect_s *audio_effect_create(audio_effect_type_e type, int rate,
+                                       int channels, audio_effect_format_e format,
+                                       size_t frames);
+int audio_effect_process(audio_effect_s *ae, void *in, void *out);
+int audio_effect_process_reference(audio_effect_s *ae, void *in, void *ref, void *out);
+void audio_effect_destroy(audio_effect_s *ae);
+size_t audio_effect_get_process_framesize(audio_effect_s *ae);
+
+#endif
diff --git a/include/audio_effect_interface.h b/include/audio_effect_interface.h
new file mode 100644 (file)
index 0000000..b56e257
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __AUDIO_EFFECT_INTERFACE_H__
+#define __AUDIO_EFFECT_INTERFACE_H__
+
+#include "audio_effect.h"
+
+typedef void *(*dl_create_t)(int, int, audio_effect_format_e, size_t);
+typedef int (*dl_process_t)(void *, char *, char *);
+typedef int (*dl_process_reference_t)(void *, char *, char *, char *);
+typedef void (*dl_destroy_t)(void *);
+
+typedef struct audio_effect_interface {
+       audio_effect_type_e type;
+       dl_create_t create;
+       dl_process_t process;
+       dl_process_reference_t process_reference;
+       dl_destroy_t destroy;
+} audio_effect_interface_s;
+
+/* Register structure for plugins */
+typedef struct audio_effect_plugin_info {
+       const char *name;
+       audio_effect_interface_s interface;
+       struct {
+               size_t frames;
+               size_t frames_msec;
+               int min_rate;
+               int max_rate;
+               int min_channels;
+               int max_channels;
+               int min_format;
+               int max_format;
+       } constraint;
+} audio_effect_plugin_info_s;
+
+audio_effect_interface_s *audio_effect_interface_new(audio_effect_type_e type,
+                                                       int rate, int channels,
+                                                       audio_effect_format_e format,
+                                                       size_t frames);
+void audio_effect_interface_free(audio_effect_interface_s *intf);
+
+void audio_effect_register_module(audio_effect_plugin_info_s *plugin_info);
+void audio_effect_unregister_module(audio_effect_plugin_info_s *plugin_info);
+
+#endif
+
diff --git a/include/audio_effect_log.h b/include/audio_effect_log.h
new file mode 100644 (file)
index 0000000..6281402
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __AUDIO_EFFECT_LOG_H__
+#define __AUDIO_EFFECT_LOG_H__
+
+#ifdef USE_DLOG
+#include <dlog.h>
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AUDIO_EFFECT"
+#define LOG_ERROR(...)                 SLOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define LOG_WARN(...)                   SLOG(LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define LOG_INFO(...)                   SLOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define LOG_DEBUG(...)                 SLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define LOG_VERBOSE(...)                 SLOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#else
+#include <stdio.h>
+#define LOG_ERROR(...)                 { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
+#define LOG_WARN(...)                   { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
+#define LOG_INFO(...)                   { fprintf(stdout, __VA_ARGS__); fprintf(stderr, "\n"); }
+#define LOG_DEBUG(...)                 { fprintf(stdout, __VA_ARGS__); fprintf(stderr, "\n"); }
+#define LOG_VERBOSE(...)                 { fprintf(stdout, __VA_ARGS__); fprintf(stderr, "\n"); }
+#endif
+
+#endif
diff --git a/include/audio_effect_util.h b/include/audio_effect_util.h
new file mode 100644 (file)
index 0000000..9286068
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#ifndef __AUDIO_EFFECT_UTIL_H__
+#define __AUDIO_EFFECT_UTIL_H__
+
+#include <audio_effect.h>
+
+size_t audio_effect_util_get_sample_size(audio_effect_format_e format);
+size_t audio_effect_util_get_frame_size(audio_effect_format_e format, int channels);
+size_t audio_effect_util_msec_to_frame(size_t msec, int rate);
+size_t audio_effect_util_msec_to_bytes(size_t msec, int rate, int channels, audio_effect_format_e format);
+void audio_effect_util_convert_s16le_to_float(size_t n, const short *a, float *b);
+void audio_effect_util_convert_float_to_s16le(size_t n, const float *a, short *b);
+
+/* TODO: parameter order */
+void audio_effect_util_interleave(const void **src, void *dst, int channels, size_t sample_size, size_t frames);
+void audio_effect_util_deinterleave(const void *src, void **dst, int channels, size_t sample_size, size_t frames);
+
+#endif
diff --git a/libaudio-effect.manifest b/libaudio-effect.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/meson.build b/meson.build
new file mode 100644 (file)
index 0000000..1591035
--- /dev/null
@@ -0,0 +1,144 @@
+project('libaudio-effect', 'c', 'cpp')
+
+version = get_option('version')
+
+platform_dep = []
+if get_option('tizen').enabled()
+  add_global_arguments('-DUSE_DLOG', language : 'c')
+  add_global_arguments('-DUSE_DLOG', language : 'cpp')
+  platform_dep += [ dependency('dlog') ]
+endif
+
+audio_effect_include_dir = include_directories('./include')
+audio_effect_plugins_install_dir = get_option('libdir')/'audio-effect-plugins/'
+
+config_data = configuration_data()
+config_data.set_quoted('DL_PLUGIN_PATH', audio_effect_plugins_install_dir)
+configure_file(output : 'config.h', configuration : config_data)
+
+# It can't find dl library that's why i replaced with cc
+#my_libdl = dependency('dl')
+cc = meson.get_compiler('c')
+
+# --- audio_effect core ---
+audio_effect_shared = shared_library('audio-effect',
+  sources: [ 'src/audio_effect.c', 'src/audio_effect_interface.c', 'src/audio_effect_util.c' ],
+  version: version,
+  soversion: '1',
+  include_directories: audio_effect_include_dir,
+  dependencies: [
+    cc.find_library('dl', required : true),
+    cc.find_library('m', required : true),
+    platform_dep,
+  ],
+  install: true,
+)
+
+# --- rnnoise plugin ---
+if get_option('ns-rnnoise').enabled()
+shared_library('audio-effect-ns-rnnoise',
+  sources: [ 'src/plugin_ns_rnnoise.c' ],
+  dependencies: [ dependency('rnnoise'), platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- aec-refcopy plugin ---
+if get_option('aec-refcopy').enabled()
+shared_library('audio-effect-aec-refcopy',
+  sources: [ 'src/plugin_aec_refcopy.c' ],
+  dependencies: [ platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- aec-speex plugin ---
+if get_option('aec-speex').enabled()
+shared_library('audio-effect-aec-speex',
+  sources: [ 'src/plugin_aec_speex.c' ],
+  dependencies: [ dependency('speexdsp'), platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- aec-webrtc plugin ---
+if get_option('aec-webrtc').enabled()
+shared_library('audio-effect-aec-webrtc',
+  sources: [ 'src/plugin_aec_webrtc.cpp' ],
+  dependencies: [ dependency('webrtc-audio-processing'), platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- amplify plugin ---
+if get_option('amplify').enabled()
+shared_library('audio-effect-amplify',
+  sources: [ 'src/plugin_amplify.c' ],
+  dependencies: [ platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- agc-speex plugin ---
+if get_option('agc-speex').enabled()
+shared_library('audio-effect-agc-speex',
+  sources: [ 'src/plugin_agc_speex.c' ],
+  dependencies: [ dependency('speexdsp'), platform_dep ],
+  include_directories: audio_effect_include_dir,
+  link_with: [audio_effect_shared],
+  install: true,
+  install_dir: audio_effect_plugins_install_dir,
+)
+endif
+
+# --- install headers ---
+install_headers('include/audio_effect.h',
+  'include/audio_effect_interface.h',
+  'include/audio_effect_util.h',
+  'include/audio_effect_log.h')
+
+# --- pkg-config install ---
+pkg = import('pkgconfig')
+pkg.generate(
+  audio_effect_shared,
+  description: 'Multimedia Framework Audio Effect library',
+  version: version,
+  name: 'libaudio-effect'
+)
+
+# --- test include ---
+if get_option('testsuite').enabled()
+  subdir('test')
+endif
+
+# --- install pkg-config ---
+#pc_cdata = configuration_data()
+#pc_cdata.set('prefix', get_option('prefix'))
+#pc_cdata.set('exec_prefix', get_option('prefix'))
+#pc_cdata.set('libdir', get_option('libdir'))
+#pc_cdata.set('includedir', get_option('includedir'))
+#pc_cdata.set('version', version)
+#
+#pkgdir = join_paths(get_option('libdir'), 'pkgconfig')
+#configure_file(
+#  input: 'libaudio-effect.pc.in',
+#  output: 'libaudio-effect.pc',
+#  configuration: pc_cdata,
+#  install_dir: pkgdir,
+#)
+
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644 (file)
index 0000000..8dcc1ac
--- /dev/null
@@ -0,0 +1,10 @@
+option('version', type: 'string', value : '0.0.1', description: 'Project version')
+option('tizen', type : 'feature', value : 'disabled', description : 'Tizen feature enable')
+option('testsuite', type : 'feature', value : 'disabled', description : 'Testsuite')
+option('ns-rnnoise', type : 'feature', value : 'disabled', description : 'rnnoise noise suppression')
+option('aec-refcopy', type : 'feature', value : 'disabled', description : 'reference copy')
+option('aec-speex', type : 'feature', value : 'disabled', description : 'speex aec')
+option('aec-webrtc', type : 'feature', value : 'disabled', description : 'webrtc aec')
+
+option('amplify', type : 'feature', value : 'disabled', description : 'Amplify')
+option('agc-speex', type : 'feature', value : 'disabled', description : 'speex agc')
diff --git a/packaging/libaudio-effect.spec b/packaging/libaudio-effect.spec
new file mode 100644 (file)
index 0000000..655932c
--- /dev/null
@@ -0,0 +1,54 @@
+Name:       libaudio-effect
+Summary:    audio effect library
+Version:    0.0.1
+Release:    0
+Group:      System/Libraries
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+
+BuildRequires:  pkgconfig(speexdsp)
+BuildRequires:  pkgconfig(rnnoise)
+BuildRequires:  pkgconfig(webrtc-audio-processing)
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  meson >= 0.53.0
+
+%description
+audio effect library
+
+%package devel
+Summary:    Audio effect library
+Group:      Multimedia/Development
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+MMSound development package for audio effect
+
+%prep
+%setup -q
+
+%build
+%{meson} -Dtizen=enabled -Dns-rnnoise=enabled -Daec-refcopy=enabled -Daec-speex=enabled -Daec-webrtc=enabled
+
+%{meson_build}
+
+%install
+%{meson_install}
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files -n %{name}
+%defattr(-,root,root,-)
+%manifest %{name}.manifest
+%license LICENSE
+%{_libdir}/*.so.*
+%{_libdir}/audio-effect-plugins/*
+
+%files devel
+%defattr(-,root,root,-)
+%manifest %{name}.manifest
+%{_libdir}/*.so
+%{_includedir}/*.h
+%{_libdir}/pkgconfig/*.pc
diff --git a/src/audio_effect.c b/src/audio_effect.c
new file mode 100644 (file)
index 0000000..992bd46
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <audio_effect.h>
+#include <audio_effect_interface.h>
+#include <audio_effect_log.h>
+
+#define container_of(ptr, type, member) ({       \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+audio_effect_s *audio_effect_create(audio_effect_type_e type, int rate, int channels,
+                                       audio_effect_format_e format, size_t frames)
+{
+       audio_effect_s *ae;
+       audio_effect_interface_s *intf;
+
+       intf = audio_effect_interface_new(type, rate, channels, format, frames);
+       if (!intf) {
+               LOG_ERROR("failed to create interface");
+               return NULL;
+       }
+
+       ae = (audio_effect_s *)calloc(1, sizeof(audio_effect_s));
+       assert(ae);
+
+       ae->intf = intf;
+       ae->priv = intf->create(rate, channels, format, frames);
+       ae->request_framesize = frames;
+
+       if (!ae->priv) {
+               audio_effect_interface_free(ae->intf);
+               free(ae);
+
+               LOG_ERROR("Failed to create plugin function");
+               return NULL;
+       }
+
+       return ae;
+}
+
+int audio_effect_process(audio_effect_s *ae, void *in, void *out)
+{
+       assert(in);
+       assert(out);
+       assert(ae);
+       assert(ae->intf);
+       assert(ae->priv);
+
+       if (!ae->intf->process) {
+               LOG_ERROR("Not supported operation");
+               return -1;
+       }
+
+       return ae->intf->process(ae->priv, in, out);
+}
+
+int audio_effect_process_reference(audio_effect_s *ae, void *in, void *ref, void *out)
+{
+       assert(in);
+       assert(out);
+       assert(ae);
+       assert(ae->intf);
+       assert(ae->priv);
+
+       if (!ae->intf->process_reference && ae->intf->process)
+               return ae->intf->process(ae->priv, in, out);
+
+       assert(ae->intf->process_reference);
+
+       return ae->intf->process_reference(ae->priv, in, ref, out);
+}
+
+void audio_effect_destroy(audio_effect_s *ae)
+{
+       assert(ae);
+       assert(ae->intf);
+       assert(ae->priv);
+       assert(ae->intf->destroy);
+
+       ae->intf->destroy(ae->priv);
+       audio_effect_interface_free(ae->intf);
+
+       free(ae);
+}
+
+size_t audio_effect_get_process_framesize(audio_effect_s *ae)
+{
+       audio_effect_plugin_info_s *plugin_info;
+
+       assert(ae);
+
+       plugin_info = container_of(ae->intf, audio_effect_plugin_info_s, interface);
+
+       if (plugin_info->constraint.frames != 0)
+               return plugin_info->constraint.frames;
+       else
+               return ae->request_framesize;
+}
diff --git a/src/audio_effect_interface.c b/src/audio_effect_interface.c
new file mode 100644 (file)
index 0000000..49f66bc
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <config.h>
+
+/* Remove annoying errors like below
+ * ISO C forbids conversion of object pointer to function pointer type
+ * when I convert void pointer to function pointer */
+#include <stdint.h>
+
+#include <audio_effect_interface.h>
+#include <audio_effect_util.h>
+#include <audio_effect_log.h>
+
+static const char *effect_path_list[] = {
+       [AUDIO_EFFECT_TYPE_AEC_SPEEX] = DL_PLUGIN_PATH "libaudio-effect-aec-speex.so",
+       [AUDIO_EFFECT_TYPE_AEC_WEBRTC] = DL_PLUGIN_PATH "libaudio-effect-aec-webrtc.so",
+       [AUDIO_EFFECT_TYPE_AEC_REFCOPY] = DL_PLUGIN_PATH "libaudio-effect-aec-refcopy.so",
+       [AUDIO_EFFECT_TYPE_NS_PSE] = DL_PLUGIN_PATH "libaudio-effect-ns-pse.so",
+       [AUDIO_EFFECT_TYPE_NS_RNNOISE] = DL_PLUGIN_PATH "libaudio-effect-ns-rnnoise.so",
+       [AUDIO_EFFECT_TYPE_AMPLIFY] = DL_PLUGIN_PATH "libaudio-effect-amplify.so",
+       [AUDIO_EFFECT_TYPE_AGC_SPEEX] = DL_PLUGIN_PATH "libaudio-effect-agc-speex.so",
+};
+
+static struct plugin_list {
+       void *handle;
+       int refcnt;
+       audio_effect_plugin_info_s *plugin_info;
+} plugin_list[AUDIO_EFFECT_TYPE_MAX];
+
+audio_effect_interface_s *audio_effect_interface_new(audio_effect_type_e type,
+                                                       int rate, int channels,
+                                                       audio_effect_format_e format,
+                                                       size_t frames)
+{
+       audio_effect_plugin_info_s *plugin_info;
+       void *handle = NULL;
+
+       assert(type < AUDIO_EFFECT_TYPE_MAX);
+
+       if (!plugin_list[type].plugin_info && plugin_list[type].refcnt == 0) {
+               handle = dlopen(effect_path_list[type], RTLD_LAZY);
+               if (!handle) {
+                       LOG_INFO("Failed to open handle. path(%s)", effect_path_list[type]);
+                       return NULL;
+               }
+               LOG_INFO("loaded module %s", effect_path_list[type]);
+       }
+
+       plugin_info = plugin_list[type].plugin_info;
+       assert(plugin_info);
+
+       /* check constraint */
+       if (plugin_info->constraint.min_rate > rate || rate > plugin_info->constraint.max_rate) {
+               LOG_ERROR("Not supported rate(%d), min_rate(%d), max_rate(%d)",
+                               rate, plugin_info->constraint.min_rate, plugin_info->constraint.max_rate);
+               goto fail;
+       }
+
+       if (plugin_info->constraint.min_channels > channels || channels > plugin_info->constraint.max_channels) {
+               LOG_ERROR("Not supported channels(%d), min_channels(%d), max_channels(%d)",
+                               channels, plugin_info->constraint.min_channels, plugin_info->constraint.max_channels);
+               goto fail;
+       }
+
+       if (plugin_info->constraint.min_format > format || format > plugin_info->constraint.max_format) {
+               LOG_ERROR("Not supported format(%d), min_format(%d), max_format(%d)",
+                               format, plugin_info->constraint.min_format, plugin_info->constraint.max_format);
+               goto fail;
+       }
+
+       if (plugin_info->constraint.frames_msec != 0)
+               plugin_info->constraint.frames = audio_effect_util_msec_to_frame(plugin_info->constraint.frames_msec, rate);
+
+       if (plugin_info->constraint.frames != 0 && plugin_info->constraint.frames != frames)
+               LOG_WARN("This plugin uses fixed frames size. Check frames size with audio_effect_get_process_framesize api");
+
+       plugin_list[type].handle = handle;
+       /* TODO handle lock */
+       plugin_list[type].refcnt += 1;
+
+       return &plugin_info->interface;
+
+fail:
+       if (handle)
+               dlclose(handle);
+
+       return NULL;
+}
+
+void audio_effect_interface_free(audio_effect_interface_s *intf)
+{
+       assert(intf);
+
+       plugin_list[intf->type].refcnt -= 1;
+
+       if (plugin_list[intf->type].refcnt == 0) {
+               LOG_INFO("unloaded module %s", effect_path_list[intf->type]);
+               dlclose(plugin_list[intf->type].handle);
+       }
+}
+
+void audio_effect_register_module(audio_effect_plugin_info_s *plugin_info)
+{
+       audio_effect_type_e type;
+
+       assert(plugin_info);
+
+       /* TODO: Currently it's array */
+       type = plugin_info->interface.type;
+
+       plugin_list[type].plugin_info = plugin_info;
+}
+
+void audio_effect_unregister_module(audio_effect_plugin_info_s *plugin_info)
+{
+       audio_effect_type_e type;
+
+       assert(plugin_info);
+
+       type = plugin_info->interface.type;
+
+       plugin_list[type].handle = NULL;
+       plugin_list[type].refcnt = 0;
+       plugin_list[type].plugin_info = NULL;
+}
diff --git a/src/audio_effect_util.c b/src/audio_effect_util.c
new file mode 100644 (file)
index 0000000..11714bf
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include <audio_effect_util.h>
+
+#define CLAMP(value, min, max) (value < min ? min : (value > max ? max : value))
+
+static struct sample_size_table {
+       int sample_size;
+       audio_effect_format_e format;
+} sample_size_table[] = {
+       { 1, AUDIO_EFFECT_FORMAT_S8 },
+       { 2, AUDIO_EFFECT_FORMAT_S16 },
+       { 3, AUDIO_EFFECT_FORMAT_S24 },
+       { 4, AUDIO_EFFECT_FORMAT_S32 },
+       { 4, AUDIO_EFFECT_FORMAT_FLOAT },
+};
+
+size_t audio_effect_util_get_sample_size(audio_effect_format_e format)
+{
+       return sample_size_table[format].sample_size;
+}
+
+size_t audio_effect_util_get_frame_size(audio_effect_format_e format, int channels)
+{
+       return sample_size_table[format].sample_size * channels;
+}
+
+size_t audio_effect_util_msec_to_frame(size_t msec, int rate)
+{
+       return rate * msec / 1000;
+}
+
+size_t audio_effect_util_msec_to_bytes(size_t msec, int rate, int channels, audio_effect_format_e format)
+{
+       return ((msec * rate) / 1000) * channels * sample_size_table[format].sample_size;
+}
+
+void audio_effect_util_convert_s16le_to_float(size_t n, const short *a, float *b)
+{
+       assert(a);
+       assert(b);
+
+       while (n--)
+               *(b++) = *(a++) * (1.0f / (1 << 15));
+}
+
+void audio_effect_util_convert_float_to_s16le(size_t n, const float *a, short *b)
+{
+       float v;
+
+       assert(a);
+       assert(b);
+
+       while (n--) {
+               v = *(a++) * (1 << 15);
+               *(b++) = (short)CLAMP(lrintf(v), -0x8000, 0x7FFF);
+       }
+}
+
+void audio_effect_util_interleave(const void **src, void *dst, int channels, size_t sample_size, size_t frames)
+{
+       size_t frame_size;
+       int i;
+
+       assert(src);
+       assert(dst);
+       assert(channels > 0);
+       assert(sample_size > 0);
+       assert(frames > 0);
+
+       frame_size = sample_size * channels;
+
+       for (i = 0; i < channels; i++) {
+               int j;
+               char *d;
+               const char *s;
+
+               s = (char *)src[i];
+               d = (char *)dst + i * sample_size;
+
+               for (j = 0; j < frames; j++) {
+                       memcpy(d, s, sample_size);
+                       s = s + sample_size;
+                       d = d + frame_size;
+               }
+       }
+}
+
+void audio_effect_util_deinterleave(const void *src, void **dst, int channels, size_t sample_size, size_t frames)
+{
+       size_t frame_size;
+       int i;
+
+       assert(src);
+       assert(dst);
+       assert(channels > 0);
+       assert(sample_size > 0);
+       assert(frames > 0);
+
+       frame_size = sample_size * channels;
+
+       for (i = 0; i < channels; i++) {
+               int j;
+               char *d;
+               const char *s;
+
+               s = (char *)src + i * sample_size;
+               d = (char *)dst[i];
+
+               for (j = 0; j < frames; j ++) {
+                       memcpy(d, s, sample_size);
+                       s = s + frame_size;
+                       d = d + sample_size;
+               }
+       }
+}
+
diff --git a/src/plugin_aec_refcopy.c b/src/plugin_aec_refcopy.c
new file mode 100644 (file)
index 0000000..98c8617
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <audio_effect_interface.h>
+#include <audio_effect_util.h>
+#include <audio_effect_log.h>
+
+struct userdata {
+       size_t frames;
+       size_t sample_size;
+       size_t frame_size;
+};
+
+void init_reference_copy(void) __attribute__ ((constructor));
+void fini_reference_copy(void) __attribute__ ((destructor));
+
+void *reference_copy_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+
+       u = (struct userdata *)malloc(sizeof(struct userdata));
+
+       u->frames = frames;
+       u->sample_size = audio_effect_util_get_sample_size(format);
+       u->frame_size = u->sample_size * channels;
+
+       LOG_INFO("reference copy init. frame(%zu)", frames);
+
+       return (void *)u;
+}
+
+int reference_copy_process_reference(void *priv, char *rec, char *ref, char *out)
+{
+       struct userdata *u = (struct userdata *)priv;
+       size_t rec_bytes, ref_bytes, actual_bytes, total_bytes;
+       char *dst = out;
+
+       assert(u);
+       assert(rec);
+       assert(ref);
+       assert(out);
+
+       rec_bytes = u->frame_size;
+       ref_bytes = u->sample_size; /* reference must be mono channel */
+       actual_bytes = rec_bytes - ref_bytes;
+       total_bytes = rec_bytes * u->frames;
+
+       while ((dst - out) < total_bytes) {
+               memcpy(dst, rec, actual_bytes);
+               memcpy(dst + actual_bytes, ref, ref_bytes);
+               dst += rec_bytes;
+               rec += rec_bytes;
+               ref += ref_bytes;
+       }
+
+       return 0;
+}
+
+void reference_copy_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+       assert(u);
+       free(u);
+}
+
+static audio_effect_plugin_info_s reference_copy = {
+       .name = "reference_copy",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_AEC_REFCOPY,
+               .create = reference_copy_create,
+               .process_reference = reference_copy_process_reference,
+               .destroy = reference_copy_destroy,
+       },
+       .constraint = {
+               .min_rate = 8000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 16,
+               .min_format = AUDIO_EFFECT_FORMAT_S8,
+               .max_format = AUDIO_EFFECT_FORMAT_S32,
+       },
+};
+
+void init_reference_copy(void)
+{
+       audio_effect_register_module(&reference_copy);
+}
+
+void fini_reference_copy(void)
+{
+       audio_effect_unregister_module(&reference_copy);
+}
+
diff --git a/src/plugin_aec_speex.c b/src/plugin_aec_speex.c
new file mode 100644 (file)
index 0000000..a305c42
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <audio_effect_interface.h>
+#include <audio_effect_log.h>
+
+#include <speex/speex.h>
+#include <speex/speex_preprocess.h>
+#include <speex/speex_echo.h>
+
+struct userdata {
+       SpeexEchoState *echo_state;
+       SpeexPreprocessState *preprocess;
+};
+
+void init_speex_aec(void) __attribute__ ((constructor));
+void fini_speex_aec(void) __attribute__ ((destructor));
+
+void *speex_aec_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+       spx_int32_t value = 1;
+
+       u = (struct userdata *)calloc(1, sizeof(struct userdata));
+       if (!u)
+               return NULL;
+
+       if (!(u->echo_state = speex_echo_state_init(frames, frames * 10))) {
+               LOG_ERROR("Failed speex_echo_state_init");
+               goto fail;
+       }
+
+       if (!(u->preprocess = speex_preprocess_state_init(frames, rate))) {
+               LOG_ERROR("Failed speex_preprocess_state_init");
+               goto fail;
+       }
+
+       if (speex_echo_ctl(u->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate)) {
+               LOG_ERROR("Failed SPEEX_ECHO_SET_SAMPLING_RATE. rate(%d)", rate);
+               goto fail;
+       }
+
+       if (speex_preprocess_ctl(u->preprocess, SPEEX_PREPROCESS_SET_AGC, &value)) {
+               LOG_ERROR("Failed SPEEX_PREPROCESS_SET_AGC");
+               goto fail;
+       }
+
+       if (speex_preprocess_ctl(u->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &value)) {
+               LOG_ERROR("Failed SPEEX_PREPROCESS_SET_DENOISE");
+               goto fail;
+       }
+
+       if (speex_preprocess_ctl(u->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &value)) {
+               LOG_ERROR("Failed SPEEX_PREPROCESS_SET_DEREVERB");
+               goto fail;
+       }
+
+       if (speex_preprocess_ctl(u->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, u->echo_state)) {
+               LOG_ERROR("Failed SPEEX_PREPROCESS_SET_ECHO_STATE");
+               goto fail;
+       }
+
+       LOG_INFO("speex echo-canceller initialized. frame(%zu), rate(%d) channels(%d)",
+                                       frames, rate, channels);
+
+       return (void *)u;
+
+fail:
+       if (u->echo_state)
+               speex_echo_state_destroy(u->echo_state);
+       if (u->preprocess)
+               speex_preprocess_state_destroy(u->preprocess);
+
+       free(u);
+
+       return NULL;
+}
+
+int speex_aec_process_reference(void *priv, char *rec, char *ref, char *out)
+{
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+       assert(rec);
+       assert(ref);
+       assert(out);
+
+       speex_echo_cancellation(u->echo_state,
+                               (const spx_int16_t *)rec,
+                               (const spx_int16_t *)ref,
+                               (spx_int16_t *)out);
+
+       speex_preprocess_run(u->preprocess, (spx_int16_t *)out);
+
+       return 0;
+}
+
+void speex_aec_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+
+       if (u->echo_state)
+               speex_echo_state_destroy(u->echo_state);
+       if (u->preprocess)
+               speex_preprocess_state_destroy(u->preprocess);
+
+       free(u);
+}
+
+static audio_effect_plugin_info_s speex_aec = {
+       .name = "speex_aec",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_AEC_SPEEX,
+               .create = speex_aec_create,
+               .process_reference = speex_aec_process_reference,
+               .destroy = speex_aec_destroy,
+       },
+       .constraint = {
+               .min_rate = 8000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 1,
+               .min_format = AUDIO_EFFECT_FORMAT_S16,
+               .max_format = AUDIO_EFFECT_FORMAT_S16,
+       },
+};
+
+void init_speex_aec(void)
+{
+       audio_effect_register_module(&speex_aec);
+}
+
+void fini_speex_aec(void)
+{
+       audio_effect_unregister_module(&speex_aec);
+}
+
diff --git a/src/plugin_aec_webrtc.cpp b/src/plugin_aec_webrtc.cpp
new file mode 100644 (file)
index 0000000..1545542
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <webrtc/modules/audio_processing/include/audio_processing.h>
+
+extern "C" {
+#include <audio_effect_interface.h>
+#include <audio_effect_util.h>
+#include <audio_effect_log.h>
+}
+
+#define DEFAULT_PROCESS_SIZE_MS 10
+#define CHANNELS_MAX 2
+
+using namespace webrtc;
+
+struct userdata {
+       AudioProcessing *ap;
+       Config config;
+       StreamConfig *sconfig;
+
+       float *rec_fbuf;
+       float *rec_dbuf[CHANNELS_MAX];
+
+       float *ref_fbuf;
+       float *ref_dbuf[CHANNELS_MAX];
+
+       float *out_fbuf;
+       float *out_dbuf[CHANNELS_MAX];
+
+       int rate;
+       int channels;
+
+       size_t frames;
+
+       /* Currently, webrtc uses fixed size(10ms) buffer */
+       int loops;
+       size_t fixed_bytes;
+       size_t fixed_frames;
+};
+
+void init_webrtc_aec(void) __attribute__ ((constructor));
+void fini_webrtc_aec(void) __attribute__ ((destructor));
+
+static void allocate_stream_buffer(struct userdata *u, size_t frames, int channels);
+static void deallocate_stream_buffer(struct userdata *u);
+
+void *webrtc_aec_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+       size_t fixed_bytes, request_bytes;
+       Config config;
+
+       u = (struct userdata *)calloc(1, sizeof(struct userdata));
+       if (!u)
+               return NULL;
+
+       fixed_bytes = audio_effect_util_msec_to_bytes(DEFAULT_PROCESS_SIZE_MS, rate, channels, format);
+       request_bytes = frames * audio_effect_util_get_frame_size(format, channels);
+
+       if (fixed_bytes > request_bytes) {
+               LOG_ERROR("frames should be bigger than %dms. frames(%zu) request_bytes(%zu)",
+                                               DEFAULT_PROCESS_SIZE_MS, frames, request_bytes);
+               goto fail;
+       }
+
+       if (request_bytes % fixed_bytes) {
+               LOG_ERROR("request_bytes(%zu) should be multiples of fixed_bytes(%zu)",
+                                               frames, request_bytes);
+               goto fail;
+       }
+
+       u->rate = rate;
+       u->channels = channels;
+
+       u->fixed_bytes = fixed_bytes;
+       u->fixed_frames = fixed_bytes / audio_effect_util_get_frame_size(format, channels);
+       u->loops = request_bytes / fixed_bytes;
+
+       config.Set<ExperimentalNs>(new ExperimentalNs(false));
+       config.Set<Intelligibility>(new Intelligibility(false));
+       config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
+
+       u->ap = AudioProcessing::Create(config);
+       if (!u->ap) {
+               LOG_ERROR("Failed to create audio processing");
+               goto fail;
+       }
+
+       u->ap->echo_cancellation()->Enable(true);
+       u->ap->gain_control()->set_mode(GainControl::kAdaptiveDigital);
+       u->ap->echo_cancellation()->set_suppression_level(EchoCancellation::kHighSuppression);
+
+       u->sconfig = new StreamConfig(rate, channels, false);
+       if (!u->sconfig) {
+               LOG_ERROR("Failed to create stream config");
+               goto fail;
+       }
+
+       u->sconfig->set_sample_rate_hz(rate);
+       u->sconfig->set_num_channels(channels);
+
+       /* webrtc supports 10ms by default */
+       u->frames = u->sconfig->num_frames();
+       if (u->frames != u->fixed_frames) {
+               LOG_ERROR("Failed to set frames. frames(%zu), fixed_frames(%zu)",
+                                               u->frames, u->fixed_frames);
+               goto fail;
+       }
+
+       allocate_stream_buffer(u, u->fixed_frames, channels);
+
+       LOG_INFO("webrtc processes init");
+
+       return (void *)u;
+
+fail:
+       if (u->ap)
+               delete u->ap;
+       if (u->sconfig)
+               delete u->sconfig;
+
+       free(u);
+
+       return NULL;
+}
+
+int webrtc_aec_process_reference(void *priv, char *rec, char *ref, char *out)
+{
+       struct userdata *u = (struct userdata *)priv;
+       size_t frames;
+       size_t float_sample_size;
+
+
+       assert(u);
+       assert(rec);
+       assert(ref);
+       assert(out);
+
+       frames = u->fixed_frames;
+       float_sample_size = audio_effect_util_get_sample_size(AUDIO_EFFECT_FORMAT_FLOAT);
+
+       for (int i = 0; i < u->loops; i++) {
+               int ret;
+
+               audio_effect_util_convert_s16le_to_float(frames * u->channels, (const short *)ref, u->ref_fbuf);
+               audio_effect_util_deinterleave(u->ref_fbuf, (void **)u->ref_dbuf, u->channels, float_sample_size, frames);
+
+               /* reference */
+               ret = u->ap->ProcessReverseStream(u->ref_dbuf, *u->sconfig, *u->sconfig, u->ref_dbuf);
+               if (ret != AudioProcessing::kNoError) {
+                       LOG_ERROR("Failed to process reverse stream");
+                       return -1;
+               }
+
+               u->ap->set_stream_delay_ms(0);
+
+               /* capture */
+               audio_effect_util_convert_s16le_to_float(frames * u->channels, (const short *)rec, u->rec_fbuf);
+               audio_effect_util_deinterleave(u->rec_fbuf, (void **)u->rec_dbuf, u->channels, float_sample_size, frames);
+
+               ret = u->ap->ProcessStream(u->rec_dbuf, *u->sconfig, *u->sconfig, u->out_dbuf);
+               if (ret != AudioProcessing::kNoError) {
+                       LOG_ERROR("Failed to process stream");
+                       return -1;
+               }
+
+               audio_effect_util_interleave((const void **)u->out_dbuf, u->out_fbuf, u->channels, float_sample_size, frames);
+               audio_effect_util_convert_float_to_s16le(frames * u->channels, u->out_fbuf, (short *)out);
+
+               rec += u->fixed_bytes;
+               ref += u->fixed_bytes;
+               out += u->fixed_bytes;
+       }
+
+       return 0;
+}
+
+void webrtc_aec_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+
+       delete u->sconfig;
+       delete u->ap;
+
+       deallocate_stream_buffer(u);
+       free(u);
+}
+
+static void deallocate_stream_buffer(struct userdata *u)
+{
+       assert(u);
+
+       for (int i = 0; i < u->channels; i++) {
+               free(u->rec_dbuf[i]);
+               free(u->ref_dbuf[i]);
+               free(u->out_dbuf[i]);
+       }
+
+       free(u->rec_fbuf);
+       free(u->ref_fbuf);
+       free(u->out_fbuf);
+}
+
+static void allocate_stream_buffer(struct userdata *u, size_t frames, int channels)
+{
+       assert(u);
+
+       u->rec_fbuf = (float *)malloc(sizeof(float) * frames * channels);
+       u->ref_fbuf = (float *)malloc(sizeof(float) * frames * channels);
+       u->out_fbuf = (float *)malloc(sizeof(float) * frames * channels);
+
+       for (int i = 0; i < channels; i++) {
+               u->rec_dbuf[i] = (float *)malloc(sizeof(float) * frames);
+               u->ref_dbuf[i] = (float *)malloc(sizeof(float) * frames);
+               u->out_dbuf[i] = (float *)malloc(sizeof(float) * frames);
+       }
+}
+
+static audio_effect_plugin_info_s webrtc_aec = {
+       .name = "webrtc_aec",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_AEC_WEBRTC,
+               .create = webrtc_aec_create,
+               .process_reference = webrtc_aec_process_reference,
+               .destroy = webrtc_aec_destroy,
+       },
+       .constraint = {
+               .frames_msec = 10,
+               .min_rate = 8000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 2,
+               .min_format = AUDIO_EFFECT_FORMAT_S16,
+               .max_format = AUDIO_EFFECT_FORMAT_S16,
+       },
+};
+
+void init_webrtc_aec(void)
+{
+       audio_effect_register_module(&webrtc_aec);
+}
+
+void fini_webrtc_aec(void)
+{
+       audio_effect_unregister_module(&webrtc_aec);
+}
+
diff --git a/src/plugin_agc_speex.c b/src/plugin_agc_speex.c
new file mode 100644 (file)
index 0000000..bc565ac
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <speex/speex_preprocess.h>
+#include <audio_effect_interface.h>
+
+struct userdata {
+       SpeexPreprocessState *st;
+       size_t frames;
+       int channels;
+       int rate;
+       audio_effect_format_e format;
+};
+
+void init_speex_agc(void) __attribute__ ((constructor));
+void fini_speex_agc(void) __attribute__ ((destructor));
+
+void *speex_agc_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+
+       u = (struct userdata *)malloc(sizeof(struct userdata));
+
+       int denoise_enabled = 1;
+       int agc_enabled = 1;
+       float target_level = 0; // The target audio level in dBFS
+       //float target_level = -20; // The target audio level in dBFS
+       float max_gain = 0; // The maximum audio gain in dB
+       //float max_gain = 30; // The maximum audio gain in dB
+       int agc_level = 8000;
+
+       SpeexPreprocessState *st;
+
+       st = speex_preprocess_state_init(frames, rate);
+
+       speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled);
+       speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &agc_enabled);
+       speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_TARGET, &target_level);
+       speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &max_gain);
+       speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &agc_level);
+
+       u->frames = frames;
+       u->st = st;
+       u->rate = rate;
+       u->channels = channels;
+       u->format = format;
+
+       return u;
+}
+
+int speex_agc_process(void *priv, char *in, char *out)
+{
+       size_t i;
+       short *src = (short *)in;
+       short *dst = (short *)out;
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(src);
+       assert(dst);
+       assert(out);
+
+       speex_preprocess_run(u->st, (spx_int16_t *)src);
+
+       for (i = 0; i < u->frames; i++) {
+               dst[i] = src[i];
+       }
+
+       return 0;
+}
+
+void speex_agc_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+
+       speex_preprocess_state_destroy(u->st);
+       free(u);
+}
+
+static audio_effect_plugin_info_s speex_agc = {
+       .name = "speex-agc",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_AGC_SPEEX,
+               .create = speex_agc_create,
+               .process = speex_agc_process,
+               .destroy = speex_agc_destroy,
+       },
+       .constraint = {
+               .min_rate = 8000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 1,
+               .min_format = AUDIO_EFFECT_FORMAT_S16,
+               .max_format = AUDIO_EFFECT_FORMAT_S16,
+       },
+};
+
+void init_speex_agc(void)
+{
+       audio_effect_register_module(&speex_agc);
+}
+
+void fini_speex_agc(void)
+{
+       audio_effect_unregister_module(&speex_agc);
+}
+
diff --git a/src/plugin_amplify.c b/src/plugin_amplify.c
new file mode 100644 (file)
index 0000000..3f782b0
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <audio_effect_interface.h>
+
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+struct userdata {
+       int rate;
+       int channels;
+       audio_effect_format_e format;
+       size_t frames;
+};
+
+void init_amplify(void) __attribute__ ((constructor));
+void fini_amplify(void) __attribute__ ((destructor));
+
+void *amplify_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+
+       u = (struct userdata *)malloc(sizeof(struct userdata));
+
+       u->rate = rate;
+       u->channels = channels;
+       u->format = format;
+       u->frames = frames;
+
+       return (void *)u;
+}
+
+int amplify_process(void *priv, char *in, char *out)
+{
+       size_t i;
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+
+       short *src = (short *)in;
+       short *dst = (short *)out;
+
+       for (i = 0; i < u->frames; i++) {
+               dst[i] = src[i] * 2.5f;
+               dst[i] = CLAMP(dst[i], -0x8000, 0x7FFF);
+       }
+
+       return 0;
+}
+
+void amplify_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+       assert(u);
+       free(u);
+}
+
+static audio_effect_plugin_info_s amplify = {
+       .name = "amplify",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_AMPLIFY,
+               .create = amplify_create,
+               .process = amplify_process,
+               .destroy = amplify_destroy,
+       },
+       .constraint = {
+               .min_rate = 8000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 1,
+               .min_format = AUDIO_EFFECT_FORMAT_S16,
+               .max_format = AUDIO_EFFECT_FORMAT_S16,
+       },
+};
+
+void init_amplify(void)
+{
+       audio_effect_register_module(&amplify);
+}
+
+void fini_amplify(void)
+{
+       audio_effect_unregister_module(&amplify);
+}
+
diff --git a/src/plugin_ns_rnnoise.c b/src/plugin_ns_rnnoise.c
new file mode 100644 (file)
index 0000000..232dbac
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <audio_effect_interface.h>
+#include <audio_effect_log.h>
+
+#include <rnnoise.h>
+
+struct userdata {
+       DenoiseState *st;
+       int rate;
+       int channels;
+       audio_effect_format_e format;
+       size_t frames;
+
+       float *buffer;
+};
+
+void init_noise_suppression_rnnoise(void) __attribute__ ((constructor));
+void fini_noise_suppression_rnnoise(void) __attribute__ ((destructor));
+
+void *noise_suppression_rnnoise_create(int rate, int channels, audio_effect_format_e format, size_t frames)
+{
+       struct userdata *u;
+
+       u = (struct userdata *)malloc(sizeof(struct userdata));
+
+       u->st = rnnoise_create(NULL);
+       u->rate = rate;
+       u->channels = channels;
+       u->format = format;
+       u->frames = frames;
+       u->buffer = (float *)malloc(sizeof(float) * frames * channels);
+
+       LOG_INFO("plugin rnnoise init. rate(%d), channels(%d), format(%d), frames(%zu)",
+                               rate, channels, format, frames);
+
+       return u;
+}
+
+int noise_suppression_rnnoise_process(void *priv, char *in, char *out)
+{
+       struct userdata *u = (struct userdata *)priv;
+       int16_t *ptr;
+       int i;
+
+       assert(u);
+       assert(in);
+       assert(out);
+
+       ptr = (int16_t *)in;
+       for (i = 0; i < u->frames; i++) {
+               u->buffer[i] = 0;
+               u->buffer[i] = ptr[i];
+       }
+
+       rnnoise_process_frame(u->st, u->buffer, u->buffer);
+
+       ptr = (int16_t *)out;
+       for (i = 0; i < u->frames; i++) {
+               ptr[i] = 0;
+               ptr[i] = u->buffer[i];
+       }
+
+       return 0;
+}
+
+void noise_suppression_rnnoise_destroy(void *priv)
+{
+       struct userdata *u = (struct userdata *)priv;
+
+       assert(u);
+       assert(u->st);
+       assert(u->buffer);
+
+       rnnoise_destroy(u->st);
+       free(u->buffer);
+       free(u);
+}
+
+static audio_effect_plugin_info_s noise_suppression_rnnoise = {
+       .name = "noise-suppression-rnnoise",
+       .interface = {
+               .type = AUDIO_EFFECT_TYPE_NS_RNNOISE,
+               .create = noise_suppression_rnnoise_create,
+               .process = noise_suppression_rnnoise_process,
+               .destroy = noise_suppression_rnnoise_destroy,
+       },
+       .constraint = {
+               .frames = 480,
+               .min_rate = 48000,
+               .max_rate = 48000,
+               .min_channels = 1,
+               .max_channels = 1,
+               .min_format = AUDIO_EFFECT_FORMAT_S16,
+               .max_format = AUDIO_EFFECT_FORMAT_S16,
+       },
+};
+
+void init_noise_suppression_rnnoise(void)
+{
+       audio_effect_register_module(&noise_suppression_rnnoise);
+}
+
+void fini_noise_suppression_rnnoise(void)
+{
+       audio_effect_unregister_module(&noise_suppression_rnnoise);
+}
+
diff --git a/test/aec_refcopy_test.c b/test/aec_refcopy_test.c
new file mode 100644 (file)
index 0000000..731deaf
--- /dev/null
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "audio_effect.h"
+
+#define FRAME_SIZE 160
+#define CHANNELS 5
+
+#define RECORDING_FILE "rec_refcopy.raw"
+#define REFERENCE_FILE "obama.raw"
+#define OUTPUT_FILE "refcopy_out.raw"
+#define MIN(a, b) (a > b ? b : a)
+
+int main(void)
+{
+       audio_effect_s *ae;
+       FILE *f_rec;
+       FILE *f_ref;
+       FILE *f_out;
+
+       struct stat st;
+       short in[FRAME_SIZE*CHANNELS];
+       short ref[FRAME_SIZE];
+       short out[FRAME_SIZE*CHANNELS];
+       off_t rec_size;
+       off_t ref_size;
+       size_t ret;
+       int loop;
+
+       size_t process_framesize = FRAME_SIZE;
+
+       int i=1;
+
+       printf("--- refcopy test start ---\n");
+
+       stat(RECORDING_FILE, &st);
+       rec_size = st.st_size;
+
+       stat(REFERENCE_FILE, &st);
+       ref_size = st.st_size;
+
+       f_rec = fopen(RECORDING_FILE, "r");
+       if (!f_rec) {
+               printf("failed to find rec.raw\n");
+               exit(-1);
+       }
+
+       f_ref = fopen(REFERENCE_FILE, "r");
+       if (!f_ref) {
+               printf("failed to find ref.raw\n");
+               exit(-1);
+       }
+
+       f_out = fopen(OUTPUT_FILE, "wb");
+       if (!f_out) {
+               printf("failed to open raw\n");
+               exit(-1);
+       }
+
+       ae = audio_effect_create(AUDIO_EFFECT_TYPE_AEC_REFCOPY, 16000, 5, AUDIO_EFFECT_FORMAT_S16, process_framesize);
+       process_framesize = audio_effect_get_process_framesize(ae);
+
+       printf("process_framesize (%zu)\n", process_framesize);
+
+       loop = MIN(rec_size / (process_framesize * CHANNELS * sizeof(short)), ref_size / (process_framesize * sizeof(short)));
+
+       while (loop-- > 0) {
+               ret = fread(in, sizeof(in), 1, f_rec);
+               if (ret == 0) {
+                       printf("Failed to read from rec file\n");
+                       exit(-1);
+               }
+
+               ret = fread(ref, sizeof(ref), 1, f_ref);
+               if (ret == 0) {
+                       printf("Failed to read from ref file\n");
+                       exit(-1);
+               }
+
+               if (audio_effect_process_reference(ae, in, ref, out) < 0) {
+                       printf("(failed!)\n");
+                       exit(-1);
+               }
+
+               fwrite(out, sizeof(out), 1, f_out);
+
+               printf("#%d frame done.\n", i++);
+       }
+
+       fclose(f_rec);
+       fclose(f_ref);
+       fclose(f_out);
+
+       audio_effect_destroy(ae);
+
+       printf("--- test end ---\n");
+
+       return 0;
+}
diff --git a/test/aec_speex_test.c b/test/aec_speex_test.c
new file mode 100644 (file)
index 0000000..67d8ed0
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "audio_effect.h"
+
+#define FRAME_SIZE 160
+
+#define RECORDING_FILE "rec.raw"
+#define REFERENCE_FILE "obama.raw"
+#define OUTPUT_FILE "aec_speex_out.raw"
+#define MIN(a, b) (a > b ? b : a)
+
+int main(void)
+{
+       audio_effect_s *ae;
+       FILE *f_rec;
+       FILE *f_ref;
+       FILE *f_out;
+
+       struct stat st;
+       short in[FRAME_SIZE];
+       short ref[FRAME_SIZE];
+       short out[FRAME_SIZE];
+       off_t rec_size;
+       off_t ref_size;
+       size_t ret;
+       int loop;
+
+       size_t process_framesize = FRAME_SIZE;
+
+       int i=1;
+
+       printf("--- aec speex test start ---\n");
+
+       stat(RECORDING_FILE, &st);
+       rec_size = st.st_size;
+
+       stat(REFERENCE_FILE, &st);
+       ref_size = st.st_size;
+
+       f_rec = fopen(RECORDING_FILE, "r");
+       if (!f_rec) {
+               printf("failed to find rec.raw\n");
+               exit(-1);
+       }
+
+       f_ref = fopen(REFERENCE_FILE, "r");
+       if (!f_ref) {
+               printf("failed to find ref.raw\n");
+               exit(-1);
+       }
+
+       f_out = fopen(OUTPUT_FILE, "wb");
+       if (!f_out) {
+               printf("failed to open raw\n");
+               exit(-1);
+       }
+
+       ae = audio_effect_create(AUDIO_EFFECT_TYPE_AEC_SPEEX, 16000, 1, AUDIO_EFFECT_FORMAT_S16, process_framesize);
+       process_framesize = audio_effect_get_process_framesize(ae);
+
+       printf("process_framesize (%zu)\n", process_framesize);
+
+       loop = MIN(rec_size / (process_framesize * sizeof(short)), ref_size / (process_framesize * sizeof(short)));
+
+       while (loop-- > 0) {
+               ret = fread(in, sizeof(in), 1, f_rec);
+               if (ret == 0) {
+                       printf("Failed to read from rec file\n");
+                       exit(-1);
+               }
+
+               ret = fread(ref, sizeof(ref), 1, f_ref);
+               if (ret == 0) {
+                       printf("Failed to read from ref file\n");
+                       exit(-1);
+               }
+
+               if (audio_effect_process_reference(ae, in, ref, out) < 0) {
+                       printf("(failed!)\n");
+                       exit(-1);
+               }
+
+               fwrite(out, sizeof(out), 1, f_out);
+
+               printf("#%d frame done.\n", i++);
+       }
+
+       fclose(f_rec);
+       fclose(f_ref);
+       fclose(f_out);
+
+       audio_effect_destroy(ae);
+
+       printf("--- test end ---\n");
+
+       return 0;
+}
diff --git a/test/aec_webrtc_test.c b/test/aec_webrtc_test.c
new file mode 100644 (file)
index 0000000..7b8f6f1
--- /dev/null
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/stat.h>
+
+#include "audio_effect.h"
+
+#define FRAME_SIZE 160
+
+#define RECORDING_FILE "rec.raw"
+#define REFERENCE_FILE "ref.raw"
+#define OUTPUT_FILE "aec_webrtc_out.raw"
+#define MIN(a, b) (a > b ? b : a)
+
+int main(void)
+{
+       audio_effect_s *ae;
+       FILE *f_rec;
+       FILE *f_ref;
+       FILE *f_out;
+
+       struct stat st;
+       short in[FRAME_SIZE];
+       short ref[FRAME_SIZE];
+       short out[FRAME_SIZE];
+       off_t rec_size;
+       off_t ref_size;
+       size_t ret;
+       int loop;
+
+       size_t process_framesize = FRAME_SIZE;
+
+       int i=1;
+
+       printf("--- aec webrtc test start ---\n");
+
+       stat(RECORDING_FILE, &st);
+       rec_size = st.st_size;
+
+       stat(REFERENCE_FILE, &st);
+       ref_size = st.st_size;
+
+       f_rec = fopen(RECORDING_FILE, "r");
+       if (!f_rec) {
+               printf("failed to find rec.raw\n");
+               exit(-1);
+       }
+
+       f_ref = fopen(REFERENCE_FILE, "r");
+       if (!f_ref) {
+               printf("failed to find ref.raw\n");
+               exit(-1);
+       }
+
+       f_out = fopen(OUTPUT_FILE, "wb");
+       if (!f_out) {
+               printf("failed to open raw\n");
+               exit(-1);
+       }
+
+       ae = audio_effect_create(AUDIO_EFFECT_TYPE_AEC_WEBRTC, 16000, 1, AUDIO_EFFECT_FORMAT_S16, process_framesize);
+       process_framesize = audio_effect_get_process_framesize(ae);
+
+       printf("process_framesize (%zu)\n", process_framesize);
+
+       loop = MIN(rec_size / (process_framesize * sizeof(short)), ref_size / (process_framesize * sizeof(short)));
+
+       while (loop-- > 0) {
+               ret = fread(in, sizeof(in), 1, f_rec);
+               if (ret == 0) {
+                       printf("Failed to read from rec file\n");
+                       exit(-1);
+               }
+
+               ret = fread(ref, sizeof(ref), 1, f_ref);
+               if (ret == 0) {
+                       printf("Failed to read from ref file\n");
+                       exit(-1);
+               }
+
+               if (audio_effect_process_reference(ae, in, ref, out) < 0) {
+                       printf("(failed!)\n");
+                       exit(-1);
+               }
+
+               fwrite(out, sizeof(out), 1, f_out);
+
+               printf("#%d frame done.\n", i++);
+       }
+
+       fclose(f_rec);
+       fclose(f_ref);
+       fclose(f_out);
+
+       audio_effect_destroy(ae);
+
+       printf("--- test end ---\n");
+
+       return 0;
+}
diff --git a/test/amplify_test.c b/test/amplify_test.c
new file mode 100644 (file)
index 0000000..1dd7e9a
--- /dev/null
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "audio_effect.h"
+
+#define FRAME_SIZE 160
+
+int main(void)
+{
+       audio_effect_s *ae;
+       FILE *fin;
+       FILE *fout;
+       char in[FRAME_SIZE*2];
+       char out[FRAME_SIZE*2];
+       size_t ret;
+
+       int i=0;
+
+       printf("--- Hello test start ---\n");
+
+       fin = fopen("obama.raw", "r");
+       if (!fin) {
+               printf("failed to find obama.raw\n");
+               exit(-1);
+       }
+
+       fout = fopen("amplify_out.raw", "wb");
+       if (!fin) {
+               printf("failed to open raw\n");
+               exit(-1);
+       }
+
+       ae = audio_effect_create(AUDIO_EFFECT_TYPE_AMPLIFY, 16000, 1, AUDIO_EFFECT_FORMAT_S16, FRAME_SIZE);
+       while (!feof(fin)) {
+               printf("#%d frame. \n", i++);
+               ret = fread(in, FRAME_SIZE*sizeof(short), 1, fin);
+               if (audio_effect_process(ae, in, out) < 0) {
+                       printf("(failed!)\n");
+               } else {
+                       printf("(success!), ret(%zu)\n", ret);
+                       fwrite(out, FRAME_SIZE*sizeof(short), 1, fout);
+               }
+       }
+
+       fclose(fin);
+       fclose(fout);
+
+       audio_effect_destroy(ae);
+
+       printf("--- Hello test end ---\n");
+
+       return 0;
+}
diff --git a/test/meson.build b/test/meson.build
new file mode 100644 (file)
index 0000000..49a0bc9
--- /dev/null
@@ -0,0 +1,46 @@
+# meson test -C build/
+
+test_list = []
+
+if get_option('amplify').enabled()
+  test_list += [[ 'amplify_test', 'amplify_test.c' ]]
+endif
+
+if get_option('ns-rnnoise').enabled()
+  test_list += [[ 'ns_rnnoise_test', 'ns_rnnoise_test.c' ]]
+endif
+
+if get_option('aec-refcopy').enabled()
+  test_list += [[ 'aec_refcopy_test', 'aec_refcopy_test.c' ]]
+endif
+
+if get_option('aec-speex').enabled()
+  test_list += [[ 'aec_speex_test', 'aec_speex_test.c' ]]
+endif
+
+if get_option('aec-webrtc').enabled()
+  test_list += [[ 'aec_webrtc_test', 'aec_webrtc_test.c' ]]
+endif
+
+env = environment()
+env.set('LD_LIBRARY_PATH', './')
+
+foreach c : test_list
+  name = c[0]
+  sources = c[1]
+
+  e = executable(name, sources,
+    link_with: [audio_effect_shared],
+    include_directories: audio_effect_include_dir,
+    install: true,
+  )
+
+  test(name, e)
+
+endforeach
+
+configure_file(input: './resources/obama.raw',  output: 'obama.raw',  copy: true)
+configure_file(input: './resources/rec.raw',  output: 'rec.raw',  copy: true)
+configure_file(input: './resources/ref.raw',  output: 'ref.raw',  copy: true)
+configure_file(input: './resources/rec_refcopy_5ch.raw',  output: 'rec_refcopy.raw',  copy: true)
+configure_file(input: './resources/airport_48k.raw',  output: 'airport_48k.raw',  copy: true)
diff --git a/test/ns_rnnoise_test.c b/test/ns_rnnoise_test.c
new file mode 100644 (file)
index 0000000..8ce98d2
--- /dev/null
@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "audio_effect.h"
+
+#define FRAME_SIZE 480
+
+int main(void)
+{
+       audio_effect_s *ae;
+       FILE *fin;
+       FILE *fout;
+       short in[FRAME_SIZE];
+       short out[FRAME_SIZE];
+       size_t ret;
+       size_t framesize = FRAME_SIZE;
+
+       int i=0;
+
+       printf("--- rnnoise start ---\n");
+
+       fin = fopen("airport_48k.raw", "r");
+       if (!fin) {
+               printf("failed to find airport_48k.raw\n");
+               exit(-1);
+       }
+
+       fout = fopen("rnnoise_out.raw", "wb");
+       if (!fin) {
+               printf("failed to open raw\n");
+               exit(-1);
+       }
+
+       ae = audio_effect_create(AUDIO_EFFECT_TYPE_NS_RNNOISE, 48000, 1, AUDIO_EFFECT_FORMAT_S16, framesize);
+       assert(ae);
+
+       framesize = audio_effect_get_process_framesize(ae);
+       printf("frame size %zu\n", framesize);
+
+       while (!feof(fin)) {
+               printf("#%d frame. \n", i++);
+               ret = fread(in, sizeof(in), 1, fin);
+               if (audio_effect_process(ae, in, out) < 0) {
+                       printf("(failed!)\n");
+               } else {
+                       printf("(success!), ret(%zu)\n", ret);
+                       fwrite(out, framesize*sizeof(short), 1, fout);
+               }
+       }
+
+       fclose(fin);
+       fclose(fout);
+
+       audio_effect_destroy(ae);
+
+       printf("--- Hello test end ---\n");
+
+       return 0;
+}
diff --git a/test/resources/airport_48k.raw b/test/resources/airport_48k.raw
new file mode 100644 (file)
index 0000000..790f343
Binary files /dev/null and b/test/resources/airport_48k.raw differ
diff --git a/test/resources/obama.raw b/test/resources/obama.raw
new file mode 100644 (file)
index 0000000..7220142
Binary files /dev/null and b/test/resources/obama.raw differ
diff --git a/test/resources/rec.raw b/test/resources/rec.raw
new file mode 100644 (file)
index 0000000..c7de21c
Binary files /dev/null and b/test/resources/rec.raw differ
diff --git a/test/resources/rec_refcopy_5ch.raw b/test/resources/rec_refcopy_5ch.raw
new file mode 100644 (file)
index 0000000..b20698f
Binary files /dev/null and b/test/resources/rec_refcopy_5ch.raw differ
diff --git a/test/resources/ref.raw b/test/resources/ref.raw
new file mode 100644 (file)
index 0000000..5cc2ab0
Binary files /dev/null and b/test/resources/ref.raw differ