--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
+
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+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,
+#)
+
--- /dev/null
+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')
--- /dev/null
+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
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+* 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;
+}
--- /dev/null
+/*
+* 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;
+ }
+ }
+}
+
--- /dev/null
+/*
+* 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);
+}
+
--- /dev/null
+/*
+* 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);
+}
+
--- /dev/null
+/*
+* 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);
+}
+
--- /dev/null
+/*
+* 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);
+}
+
--- /dev/null
+/*
+* 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(&lify);
+}
+
+void fini_amplify(void)
+{
+ audio_effect_unregister_module(&lify);
+}
+
--- /dev/null
+/*
+* 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);
+}
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+# 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)
--- /dev/null
+#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;
+}