src/tizenaudio-source2.h \
src/tizenaudio-util.c \
src/tizenaudio-util.h \
- src/preprocessor/preprocessor-def.h
+ src/preprocessor/processor-def.h
libtizenaudio_util_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version
libtizenaudio_util_la_LIBADD = $(AM_LIBADD) $(PA_LIBS) libhal-interface.la libprocessor.la
libtizenaudio_util_la_CFLAGS = $(MODULE_CFLAGS)
module_tizenaudio_source2_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source2
libprocessor_la_SOURCES = \
- src/preprocessor/method_speex.c \
- src/preprocessor/method_rnnoise.c \
- src/preprocessor/method_reference_copy.c \
- src/preprocessor/method_webrtc.cpp \
src/preprocessor/reference_method_filesrc.c \
src/preprocessor/processor.c \
src/preprocessor/processor.h \
+ src/preprocessor/processor-def.h \
src/preprocessor/method_factory.c \
src/preprocessor/method_factory.h \
src/preprocessor/processor_reference.c \
src/preprocessor/processor_holder.c \
src/preprocessor/processor_holder.h
libprocessor_la_LDFLAGS = $(AM_LDFLAGS) $(PA_LDFLAGS) -avoid-version
-libprocessor_la_LIBADD = $(AM_LIBADD) $(LIBSPEEX_LIBS) $(RNNOISE_LIBS) $(WEBRTC_LIBS)
-libprocessor_la_CFLAGS = $(AM_CFLAGS) $(PA_CFLAGS) $(LIBSPEEX_CFLAGS) $(RNNOISE_CFLAGS)
+libprocessor_la_LIBADD = $(AM_LIBADD) $(AUDIOEFFECT_LIBS)
+libprocessor_la_CFLAGS = $(AM_CFLAGS) $(PA_CFLAGS) $(AUDIOEFFECT_CFLAGS)
libprocessor_la_CPPFLAGS = $(AM_CFLAGS) $(PA_CFLAGS) $(WEBRTC_CFLAGS) -DSUPPORT_METHOD_WEBRTC -std=c++17
module_tizenaudio_preprocessor_la_SOURCES = src/preprocessor/module-tizenaudio-preprocessor.c
AC_SUBST(HALAPIAUDIO_CFLAGS)
AC_SUBST(HALAPIAUDIO_LIBS)
-PKG_CHECK_MODULES(SPEEX, speexdsp)
-AC_SUBST(SPEEX_CFLAGS)
-AC_SUBST(SPEEX_LIBS)
+PKG_CHECK_MODULES(AUDIOEFFECT, libaudio-effect)
+AC_SUBST(AUDIOEFFECT_CFLAGS)
+AC_SUBST(AUDIOEFFECT_LIBS)
-PKG_CHECK_MODULES(WEBRTC, webrtc-audio-processing)
-AC_SUBST(WEBRTC_CFLAGS)
-AC_SUBST(WEBRTC_LIBS)
-
-PKG_CHECK_MODULES(RNNOISE, rnnoise)
-AC_SUBST(RNNOISE_CFLAGS)
-AC_SUBST(RNNOISE_LIBS)
dnl use hal tc ------------------------------------------------------------
AC_ARG_ENABLE(haltc, AC_HELP_STRING([--enable-haltc], [using haltc]),
Name: pulseaudio-modules-tizen
Summary: Pulseaudio modules for Tizen
-Version: 15.0.41
+Version: 15.0.42
Release: 0
Group: Multimedia/Audio
License: LGPL-2.1+
BuildRequires: pkgconfig(speexdsp)
BuildRequires: pkgconfig(rnnoise)
BuildRequires: pkgconfig(webrtc-audio-processing)
+BuildRequires: pkgconfig(libaudio-effect)
BuildRequires: pulseaudio
BuildRequires: m4
Requires(post): /sbin/ldconfig
#include "processor.h"
-extern void *speex_create(size_t nframes, pa_sample_spec *ss);
-extern int32_t speex_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
-extern int32_t speex_destroy(void *priv);
-
-extern void *webrtc_audio_create(size_t nframes, pa_sample_spec *ss);
-extern int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
-extern int32_t webrtc_audio_destroy(void *priv);
-
-extern void *reference_copy_create(size_t nframes, pa_sample_spec *ss);
-extern int32_t reference_copy_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
-extern int32_t reference_copy_destroy(void *priv);
-
-extern void *rnnoise_ns_create(size_t nframes, pa_sample_spec *ss);
-extern int32_t rnnoise_ns_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
-extern int32_t rnnoise_ns_destroy(void *priv);
-
extern void *processor_reference_filesrc_create(pa_sample_spec *ss);
extern size_t processor_reference_filesec_read(void *priv, void *ref, size_t length);
extern void processor_reference_filesrc_destroy(void *priv);
-pa_processor_method *pa_processor_method_create(pa_processor_method_t type) {
- pa_processor_method *m = pa_xnew0(pa_processor_method, 1);
-
- switch (type) {
- case PROCESSOR_METHOD_SPEEX:
- m->name = "speex";
- m->create = speex_create;
- m->process = speex_process;
- m->destroy = speex_destroy;
- break;
- case PROCESSOR_METHOD_WEBRTC:
- m->name = "webrtc";
- m->create = webrtc_audio_create;
- m->process = webrtc_audio_process;
- m->destroy = webrtc_audio_destroy;
- break;
- case PROCESSOR_METHOD_REFERENCE_COPY:
- m->name = "reference_copy";
- m->create = reference_copy_create;
- m->process = reference_copy_process;
- m->destroy = reference_copy_destroy;
- break;
- case PROCESSOR_METHOD_RNNOISE:
- m->name = "rnnoise";
- m->create = rnnoise_ns_create;
- m->process = rnnoise_ns_process;
- m->destroy = rnnoise_ns_destroy;
- break;
- default:
- pa_assert_not_reached();
- break;
- }
-
- return m;
-}
-
pa_processor_reference_method *pa_processor_reference_method_create(pa_processor_reference_method_t type) {
pa_processor_reference_method *m = pa_xnew0(pa_processor_reference_method, 1);
PROCESSOR_METHOD_WEBRTC,
PROCESSOR_METHOD_REFERENCE_COPY,
PROCESSOR_METHOD_RNNOISE,
+ PROCESSOR_METHOD_NONE_PSE,
PROCESSOR_METHOD_MAX,
} pa_processor_method_t;
PROCESSOR_REFERENCE_METHOD_MAX,
} pa_processor_reference_method_t;
-typedef struct pa_processor_method {
- const char *name;
- void *(*create)(size_t nframes, pa_sample_spec *ss);
- int32_t (*process)(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
- int32_t (*destroy)(void *priv);
-} pa_processor_method;
-
typedef struct pa_processor_reference_method {
const char *name;
void *(*create)(pa_sample_spec *ss);
void (*destroy)(void *priv);
} pa_processor_reference_method;
-pa_processor_method *pa_processor_method_create(pa_processor_method_t type);
pa_processor_reference_method *pa_processor_reference_method_create(pa_processor_reference_method_t type);
#endif
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2022 Jaechul Lee <jcsing.lee@samsung.com>
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <pulse/xmalloc.h>
-#include <pulse/sample.h>
-#include <pulse/channelmap.h>
-#include <pulsecore/log.h>
-#include <pulsecore/macro.h>
-
-struct reference_copy {
- size_t nframes;
- pa_sample_spec ss;
- int reference_channels;
-};
-
-void *reference_copy_create(size_t nframes, pa_sample_spec *ss) {
- struct reference_copy *rc;
-
- pa_assert(ss);
-
- rc = pa_xnew0(struct reference_copy, 1);
- rc->nframes = nframes;
- rc->ss = *ss;
-
- return rc;
-}
-
-int32_t reference_copy_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) {
- struct reference_copy *rc = priv;
- size_t rec_bytes, ref_bytes, actual_bytes, total_bytes;
- int8_t *dst = out;
-
- pa_assert(rc);
- pa_assert(rec);
- pa_assert(ref);
- pa_assert(out);
-
- rec_bytes = pa_frame_size(&rc->ss);
- ref_bytes = pa_sample_size(&rc->ss); /* reference must be 1 channel */
- actual_bytes = rec_bytes - ref_bytes;
- total_bytes = rec_bytes * rc->nframes;
-
- 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;
-}
-
-int32_t reference_copy_destroy(void *priv) {
- struct reference_copy *rc = priv;
-
- pa_assert(rc);
-
- pa_xfree(rc);
-
- return 0;
-}
-
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2023 Jaechul Lee <jcsing.lee@samsung.com>
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <pulse/xmalloc.h>
-#include <pulse/sample.h>
-#include <pulsecore/log.h>
-#include <pulsecore/macro.h>
-
-#include <rnnoise.h>
-
-#include <assert.h>
-
-struct method_rnnoise {
- DenoiseState *st;
- pa_sample_spec ss;
- size_t frames;
- float *buffer;
-};
-
-void *rnnoise_ns_create(size_t nframes, pa_sample_spec *ss) {
- struct method_rnnoise *rnnoise = NULL;
-
- pa_assert(ss);
-
- if (ss->channels >= 2 || ss->format != PA_SAMPLE_S16LE || ss->rate != 48000) {
- pa_log_error("rnnoise limitation. not support rate(%d) ch(%d) format(%d)",
- ss->rate, ss->channels, ss->format);
- return NULL;
- }
-
- rnnoise = pa_xnew0(struct method_rnnoise, 1);
- rnnoise->st = rnnoise_create(NULL);
- rnnoise->ss = *ss;
- rnnoise->frames = nframes;
- rnnoise->buffer = pa_xnew(float, nframes * ss->channels);
-
- pa_log_info("rnnoise initialized. frame(%zu), rate(%d) channels(%d)",
- nframes, ss->rate, ss->channels);
-
- return rnnoise;
-}
-
-int32_t rnnoise_ns_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) {
- struct method_rnnoise *rnnoise = priv;
- int16_t *ptr;
- int i;
-
- assert(rec);
- assert(out);
-
- ptr = (int16_t *)rec;
- for (i=0; i<rnnoise->frames; i++) {
- rnnoise->buffer[i] = 0;
- rnnoise->buffer[i] = ptr[i];
- }
-
- rnnoise_process_frame(rnnoise->st, rnnoise->buffer, rnnoise->buffer);
-
- ptr = (int16_t *)out;
- for (i=0; i<rnnoise->frames; i++) {
- ptr[i] = 0;
- ptr[i] = rnnoise->buffer[i];
- }
-
- return 0;
-}
-
-int32_t rnnoise_ns_destroy(void *priv) {
- struct method_rnnoise *rnnoise = priv;
-
- pa_assert(rnnoise);
-
- rnnoise_destroy(rnnoise->st);
-
- pa_xfree(rnnoise->buffer);
- pa_xfree(rnnoise);
-
- return 0;
-}
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2021 Jaechul Lee <jcsing.lee@samsung.com>
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <pulse/xmalloc.h>
-#include <pulse/sample.h>
-#include <pulsecore/log.h>
-#include <pulsecore/macro.h>
-
-#include <speex/speex.h>
-#include <speex/speex_preprocess.h>
-#include <speex/speex_echo.h>
-
-#include <assert.h>
-
-struct method_speex {
- SpeexEchoState *echo_state;
- SpeexPreprocessState *preprocess;
-};
-
-void *speex_create(size_t nframes, pa_sample_spec *ss) {
- struct method_speex *speex = NULL;
- spx_int32_t value = 1;
- int rate;
-
- pa_assert(ss);
-
- if (ss->channels > 2 || ss->format != PA_SAMPLE_S16LE) {
- pa_log_error("Invalid channels(%d) or format(%d)", ss->channels, ss->format);
- return NULL;
- }
-
- speex = pa_xnew0(struct method_speex, 1);
-
- /* TODO: need to check. weird behavior */
- if (ss->channels == 2)
- nframes *= 2;
-
- speex->echo_state = speex_echo_state_init(nframes, nframes * 10);
-
- if (!speex->echo_state) {
- pa_log_error("_echo_state_init_mc failed");
- goto fail;
- }
-
- rate = ss->rate;
- if (!(speex->preprocess = speex_preprocess_state_init(nframes, rate))) {
- pa_log_error("_preprocess_state_init failed");
- goto fail;
- }
-
- if (speex_echo_ctl(speex->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate)) {
- pa_log_error("_echo_ctl SET_SAMPLING_RATE failed");
- goto fail;
- }
-
- if (speex_preprocess_ctl(speex->preprocess, SPEEX_PREPROCESS_SET_AGC, &value)) {
- pa_log_error("_echo_ctl SPEEX_PREPROCESS_SET_AGC failed");
- goto fail;
- }
-
- if (speex_preprocess_ctl(speex->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &value)) {
- pa_log_error("_echo_ctl SPEEX_PREPROCESS_SET_DENOISE failed");
- goto fail;
- }
-
- if (speex_preprocess_ctl(speex->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &value)) {
- pa_log_error("_echo_ctl SPEEX_PREPROCESS_SET_DEREVERB failed");
- goto fail;
- }
-
- if (speex_preprocess_ctl(speex->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE, speex->echo_state)) {
- pa_log_error("_echo_ctl SET_ECHO_STATE failed");
- goto fail;
- }
-
- pa_log_info("speex echo-canceller initialized. frame(%zu), rate(%d) channels(%d)",
- nframes, ss->rate, ss->channels);
-
- return speex;
-
-fail:
- pa_xfree(speex);
-
- return NULL;
-}
-
-int32_t speex_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) {
- struct method_speex *speex = priv;
-
- assert(rec);
- assert(ref);
- assert(out);
-
- speex_echo_cancellation(speex->echo_state,
- (const spx_int16_t *)rec,
- (const spx_int16_t *)ref,
- (spx_int16_t *)out);
-
- speex_preprocess_run(speex->preprocess, (spx_int16_t *)out);
-
- return 0;
-}
-
-int32_t speex_destroy(void *priv) {
- struct method_speex *speex = priv;
-
- if (speex->echo_state)
- speex_echo_state_destroy(speex->echo_state);
- if (speex->preprocess)
- speex_preprocess_state_destroy(speex->preprocess);
-
- pa_xfree(speex);
-
- return 0;
-}
+++ /dev/null
-/***
- This file is part of PulseAudio.
-
- Copyright 2021 Jaechul Lee <jcsing.lee@samsung.com>
-
- PulseAudio is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; either version 2.1 of the License,
- or (at your option) any later version.
-
- PulseAudio is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with PulseAudio; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <pulse/cdecl.h>
-
-#include <webrtc/modules/audio_processing/include/audio_processing.h>
-
-#define DEFAULT_PROCESS_SIZE_MS 10
-
-using namespace webrtc;
-
-PA_C_DECL_BEGIN
-#include <pulsecore/log.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/sconv.h>
-#include <pulsecore/sample-util.h>
-#include <pulse/xmalloc.h>
-#include <pulse/sample.h>
-#include <pulse/timeval.h>
-#include <stdint.h>
-
-static void allocate_stream_buffer(struct method_webrtc *webrtc, size_t nframes);
-static void deallocate_stream_buffer(struct method_webrtc *webrtc);
-static void convert_s16_to_float(float *dst, int16_t *src, size_t n);
-static void convert_float_to_s16(int16_t *dst, float *src, size_t n);
-
-void *webrtc_audio_create(size_t nframes, pa_sample_spec *ss);
-int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out);
-int32_t webrtc_audio_destroy(void *priv);
-PA_C_DECL_END
-
-struct method_webrtc {
- AudioProcessing *ap;
- Config config;
- StreamConfig *sconfig;
-
- float *rec_fbuf;
- float *rec_dbuf[PA_CHANNELS_MAX];
-
- float *ref_fbuf;
- float *ref_dbuf[PA_CHANNELS_MAX];
-
- float *out_fbuf;
- float *out_dbuf[PA_CHANNELS_MAX];
-
- pa_sample_spec ss;
- size_t frames;
-
- /* Currently, webrtc uses fixed size(10ms) buffer */
- int loops;
- size_t fixed_bytes;
- size_t fixed_frames;
-};
-
-void *webrtc_audio_create(size_t nframes, pa_sample_spec *ss) {
- struct method_webrtc *webrtc = NULL;
- size_t fixed_bytes, request_bytes;
- Config config;
-
- pa_assert(ss);
-
- if (ss->channels > 2 || ss->format != PA_SAMPLE_S16LE) {
- pa_log_error("Invalid channels (%d) or format (%d)", ss->channels, ss->format);
- return NULL;
- }
-
- fixed_bytes = pa_usec_to_bytes(DEFAULT_PROCESS_SIZE_MS * PA_USEC_PER_MSEC, ss);
- request_bytes = nframes * pa_frame_size(ss);
-
- if (fixed_bytes > request_bytes) {
- pa_log_error("nframes should be bigger than %dms. nframes(%zu) request_bytes(%zu)",
- DEFAULT_PROCESS_SIZE_MS, nframes, request_bytes);
- return NULL;
- }
-
- if (request_bytes % fixed_bytes) {
- pa_log_error("request_bytes(%zu) should be multiples of fixed_bytes(%zu)",
- nframes, request_bytes);
- return NULL;
- }
-
- webrtc = pa_xnew0(struct method_webrtc, 1);
- webrtc->ss = *ss;
- webrtc->fixed_bytes = fixed_bytes;
- webrtc->fixed_frames = fixed_bytes / pa_frame_size(ss);
- webrtc->loops = request_bytes / fixed_bytes;
-
- config.Set<ExperimentalNs>(new ExperimentalNs(false));
- config.Set<Intelligibility>(new Intelligibility(false));
- config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
-
- webrtc->ap = AudioProcessing::Create(config);
- if (!webrtc->ap) {
- pa_log_error("Failed to create audio processing");
- goto fail;
- }
-
- webrtc->ap->echo_cancellation()->Enable(true);
-
- webrtc->ap->gain_control()->set_mode(GainControl::kAdaptiveDigital);
- //webrtc->ap->gain_control()->set_target_level_dbfs(30);
- //webrtc->ap->gain_control()->set_stream_analog_level(30);
- webrtc->ap->echo_cancellation()->set_suppression_level(static_cast<EchoCancellation::SuppressionLevel>(1));
-
- webrtc->sconfig = new StreamConfig(ss->rate, ss->channels, false);
- if (!webrtc->sconfig) {
- pa_log_error("Failed to create stream config");
- goto fail;
- }
-
- webrtc->sconfig->set_sample_rate_hz(ss->rate);
- webrtc->sconfig->set_num_channels(ss->channels);
-
- /* webrtc supports 10ms by default */
- webrtc->frames = webrtc->sconfig->num_frames();
- if (webrtc->frames != webrtc->fixed_frames) {
- pa_log_error("Failed to set frames. frames(%zu), fixed_frames(%zu)",
- webrtc->frames, webrtc->fixed_frames);
- goto fail;
- }
-
- allocate_stream_buffer(webrtc, webrtc->fixed_frames);
-
- pa_log_info("webrtc processes request block(%llumsec) block(%llumsec) n(%d)\n",
- pa_bytes_to_usec(request_bytes, ss) / PA_USEC_PER_MSEC,
- pa_bytes_to_usec(fixed_bytes, ss) / PA_USEC_PER_MSEC,
- webrtc->loops);
-
- return webrtc;
-
-fail:
- if (webrtc->ap)
- delete webrtc->ap;
- if (webrtc->sconfig)
- delete webrtc->sconfig;
-
- pa_xfree(webrtc);
-
- return NULL;
-}
-
-int32_t webrtc_audio_process(void *priv, int8_t *rec, int8_t *ref, int8_t *out) {
- struct method_webrtc *webrtc = (struct method_webrtc *)priv;
- pa_sample_spec ss;
- size_t frames;
-
- pa_assert(webrtc);
- pa_assert(rec);
- pa_assert(ref);
- pa_assert(out);
-
- ss.format = PA_SAMPLE_FLOAT32LE;
- ss.rate = webrtc->ss.rate;
- ss.channels = webrtc->ss.channels;
-
- frames = webrtc->fixed_frames;
-
- for (int i = 0; i < webrtc->loops; i++) {
- int ret;
-
- convert_s16_to_float(webrtc->ref_fbuf, (int16_t *)ref, frames * ss.channels);
- pa_deinterleave(webrtc->ref_fbuf, (void **)webrtc->ref_dbuf, ss.channels,
- pa_sample_size(&ss), frames);
-
- /* reference */
- ret = webrtc->ap->ProcessReverseStream(webrtc->ref_dbuf,
- *webrtc->sconfig,
- *webrtc->sconfig,
- webrtc->ref_dbuf);
- if (ret != AudioProcessing::kNoError) {
- pa_log_error("Failed to process reverse stream");
- return -1;
- }
-
- webrtc->ap->set_stream_delay_ms(0);
-
- /* capture */
- convert_s16_to_float(webrtc->rec_fbuf, (int16_t *)rec, frames * ss.channels);
- pa_deinterleave(webrtc->rec_fbuf, (void **)webrtc->rec_dbuf, ss.channels,
- pa_sample_size(&ss), frames);
-
- ret = webrtc->ap->ProcessStream(webrtc->rec_dbuf,
- *webrtc->sconfig,
- *webrtc->sconfig,
- webrtc->out_dbuf);
- if (ret != AudioProcessing::kNoError) {
- pa_log_error("Failed to process stream");
- return -1;
- }
-
- pa_interleave((const void **)webrtc->out_dbuf, ss.channels, webrtc->out_fbuf,
- pa_sample_size(&ss), frames);
- convert_float_to_s16((int16_t *)out, webrtc->out_fbuf, frames * ss.channels);
-
- rec += webrtc->fixed_bytes;
- ref += webrtc->fixed_bytes;
- out += webrtc->fixed_bytes;
- }
-
- return 0;
-}
-
-int32_t webrtc_audio_destroy(void *priv) {
- struct method_webrtc *webrtc = (struct method_webrtc *)priv;
-
- pa_assert(webrtc);
-
- delete webrtc->sconfig;
- delete webrtc->ap;
-
- deallocate_stream_buffer(webrtc);
- pa_xfree(webrtc);
-
- return 0;
-}
-
-static void deallocate_stream_buffer(struct method_webrtc *webrtc) {
- pa_assert(webrtc);
-
- for (int i = 0; i < webrtc->ss.channels; i++) {
- pa_xfree(webrtc->rec_dbuf[i]);
- pa_xfree(webrtc->ref_dbuf[i]);
- pa_xfree(webrtc->out_dbuf[i]);
- }
-
- pa_xfree(webrtc->rec_fbuf);
- pa_xfree(webrtc->ref_fbuf);
- pa_xfree(webrtc->out_fbuf);
-}
-
-static void allocate_stream_buffer(struct method_webrtc *webrtc, size_t nframes) {
- int channels;
-
- pa_assert(webrtc);
-
- channels = webrtc->ss.channels;
-
- webrtc->rec_fbuf = pa_xnew(float, nframes * channels);
- webrtc->ref_fbuf = pa_xnew(float, nframes * channels);
- webrtc->out_fbuf = pa_xnew(float, nframes * channels);
-
- for (int i = 0; i < channels; i++) {
- webrtc->rec_dbuf[i] = pa_xnew(float, nframes);
- webrtc->ref_dbuf[i] = pa_xnew(float, nframes);
- webrtc->out_dbuf[i] = pa_xnew(float, nframes);
- }
-}
-
-static void convert_s16_to_float(float *dst, int16_t *src, size_t n) {
- pa_assert(dst);
- pa_assert(src);
-
- ((pa_convert_func_t)pa_get_convert_to_float32ne_function(PA_SAMPLE_S16LE))(n, src, dst);
-}
-
-static void convert_float_to_s16(int16_t *dst, float *src, size_t n) {
- pa_assert(dst);
- pa_assert(src);
-
- ((pa_convert_func_t)pa_get_convert_to_s16ne_function(PA_SAMPLE_FLOAT32LE))(n, src, dst);
-}
-
#include <pulse/util.h>
#include <pulse/timeval.h>
-#include "preprocessor-def.h"
#include "processor.h"
#include "processor_holder.h"
static pa_processor_holder *build_processor_holder(pa_core *core, pa_source_output_new_data *data) {
const char *state = NULL;
const char *processors_list;
- char *processor_str;
+ char *processor_str = NULL;
pa_processor_holder *holder;
pa_usec_t process_usec;
pa_assert(core);
pa_assert(data);
- holder = pa_processor_holder_new(&data->sample_spec);
+ holder = pa_processor_holder_new(core, &data->sample_spec);
if (!holder) {
pa_log_error("Failed to allocate pa_processor_holder");
return NULL;
while ((processor_str = pa_split(processors_list, ",", &state))) {
pa_processor *processor;
- pa_processor_method_t method = pa_processor_method_enum(processor_str);
+ pa_processor_method_t method;
+
+ if (pa_processor_method_enum(processor_str, &method) < 0) {
+ pa_log_error("Failed to get method. processor_str(%s)", processor_str);
+ goto fail;
+ }
processor = pa_processor_new(core, process_usec / PA_USEC_PER_MSEC,
&data->sample_spec, method);
if (!processor) {
pa_log_error("Failed to create pa_processor. preprocessor(aec) will be disabled");
- continue;
+ goto fail;
}
/* reference */
if (pa_processor_method_need_reference_structure(method)) {
pa_sample_spec request_ss;
pa_processor_reference *reference;
- pa_sink *sink = convert_reference_str_to_sink(core,
- pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_SINK));
+ const char *ref_sink;
+ pa_sink *sink;
- pa_assert(sink);
+ ref_sink = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_SINK);
+ if (!ref_sink) {
+ pa_log_error("Failed to get ref sink");
+ goto fail;
+ }
+
+ sink = convert_reference_str_to_sink(core, ref_sink);
+ if (!sink) {
+ pa_log_error("Failed to convert sink");
+ goto fail;
+ }
request_ss = data->sample_spec;
if (method == PROCESSOR_METHOD_REFERENCE_COPY) {
if (!reference) {
pa_processor_free(processor);
pa_log_error("Failed to create reference custom. processor_str(%s)", processor_str);
- continue;
+ goto fail;
}
/* holder -> reference -> processor */
pa_processor_reference_free(reference);
pa_processor_free(processor);
pa_log_error("Failed to connect holder to reference");
- continue;
+ goto fail;
}
}
}
return holder;
+
+fail:
+ if (holder)
+ pa_processor_holder_free(holder);
+ if (processor_str)
+ pa_xfree(processor_str);
+
+ return NULL;
}
static void destroy_source_output_preprocessor(pa_source_output *o) {
static int preprocess(pa_source_output *o, pa_memchunk *chunk, pa_memchunk *ochunk) {
pa_processor_holder *holder;
+ int ret;
pa_assert(o);
pa_assert(chunk);
/* chunk must contain resampled sound pcm */
pa_processor_holder_push_data(holder, chunk);
- if (pa_processor_holder_pump(holder) < 0) {
- pa_log_warn("Failed to pump holder");
- return -1;
+ ret = pa_processor_holder_pump(holder);
+ if (ret != PROCESSOR_OK) {
+ if (ret != -PROCESSOR_ERR_BUFFERING)
+ pa_log_warn("Failed to pump holder. ret(%x)", ret);
+
+ return ret;
}
- /* TODO: need to check return value for pse */
pa_processor_holder_pull_data(holder, ochunk);
return 0;
holder = build_processor_holder(c, data);
if (!holder) {
pa_log_error("Failed to build holder");
- return PA_HOOK_OK;
+ return PA_HOOK_CANCEL;
}
data->processor_holder = (void *)holder;
pa_log_debug("Thread starting up");
+#if 0 // FIXME: RT disabled due to segfault when invoking tflite
if (u->core->realtime_scheduling)
pa_thread_make_realtime(u->core->realtime_priority);
+#endif
pa_thread_mq_install(&u->thread_mq);
#include <config.h>
#endif
+#include <pulsecore/source.h>
+#include <pulsecore/sink.h>
+
+typedef enum processor_error_code {
+ PROCESSOR_OK,
+ PROCESSOR_ERR_INVALID,
+ PROCESSOR_ERR_BUFFERING,
+} processor_error_code_t;
+
enum {
PA_SOURCE_MESSAGE_PREPROCESSOR_ADD_OUTPUT = PA_SOURCE_MESSAGE_MAX + 1, /* 21 */
PA_SOURCE_MESSAGE_PREPROCESSOR_REMOVE_OUTPUT,
return pa_usec_to_bytes(usec, spec) / pa_frame_size(spec);
}
+static pa_usec_t pa_processor_frame_to_usec(size_t frame, pa_sample_spec *spec) {
+ return pa_bytes_to_usec(pa_frame_size(spec) * frame, spec);
+}
+
+static int pa_processor_convert_method(pa_processor_method_t method, audio_effect_type_e *type) {
+ int ret = 0;
+
+ switch (method) {
+ case PROCESSOR_METHOD_SPEEX:
+ *type = AUDIO_EFFECT_TYPE_AEC_SPEEX;
+ break;
+ case PROCESSOR_METHOD_WEBRTC:
+ *type = AUDIO_EFFECT_TYPE_AEC_WEBRTC;
+ break;
+ case PROCESSOR_METHOD_REFERENCE_COPY:
+ *type = AUDIO_EFFECT_TYPE_AEC_REFCOPY;
+ break;
+ case PROCESSOR_METHOD_RNNOISE:
+ *type = AUDIO_EFFECT_TYPE_NS_RNNOISE;
+ break;
+ case PROCESSOR_METHOD_NONE_PSE:
+ *type = AUDIO_EFFECT_TYPE_NS_PSE;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static int pa_processor_convert_format(pa_sample_format_t f, audio_effect_format_e *format) {
+ int ret = 0;
+
+ switch(f) {
+ case PA_SAMPLE_U8:
+ *format = AUDIO_EFFECT_FORMAT_S8;
+ break;
+ case PA_SAMPLE_S16LE:
+ *format = AUDIO_EFFECT_FORMAT_S16;
+ break;
+ case PA_SAMPLE_S24LE:
+ *format = AUDIO_EFFECT_FORMAT_S24;
+ break;
+ case PA_SAMPLE_S32LE:
+ *format = AUDIO_EFFECT_FORMAT_S32;
+ break;
+ case PA_SAMPLE_FLOAT32LE:
+ *format = AUDIO_EFFECT_FORMAT_FLOAT;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
pa_processor *pa_processor_new(pa_core *core,
uint32_t process_msec,
pa_sample_spec *ss,
pa_processor_method_t method) {
pa_processor *processor;
pa_memchunk silence;
+ size_t process_framesize;
+
+ audio_effect_type_e type;
+ audio_effect_format_e format;
pa_assert(core);
pa_assert(ss);
processor = pa_xnew0(pa_processor, 1);
processor->core = core;
- processor->interface = pa_processor_method_create(method);
processor->process_usec = process_msec * PA_USEC_PER_MSEC;
processor->ss = *ss;
processor->method = method;
processor->process_frames = pa_processor_usec_to_frame(processor->process_usec, &processor->ss);
processor->process_bytes = pa_usec_to_bytes(processor->process_usec, &processor->ss);
- pa_assert(processor->interface->create);
- pa_assert(processor->interface->process);
- pa_assert(processor->interface->destroy);
+ if (pa_processor_convert_method(method, &type) < 0) {
+ pa_log_error("Failed to convert audio-effect type. method(%d), type(%d)", method, type);
+ return NULL;
+ }
+
+ if (pa_processor_convert_format(ss->format, &format) < 0) {
+ pa_log_error("Failed to convert audio-effect format. format(%d), audio_effect_format(%d)", ss->format, format);
+ return NULL;
+ }
- if (!(processor->priv = processor->interface->create(processor->process_frames, &processor->ss))) {
- pa_log_error("Failed to create processor. rate(%d), channels(%d).", processor->ss.rate, processor->ss.channels);
- pa_xfree(processor);
+ processor->audio_effect = audio_effect_create(type, ss->rate, ss->channels, format, processor->process_frames);
+ if (!processor->audio_effect) {
+ pa_log_error("Failed to create audio effect. type(%d), rate(%d), ch(%d), format(%d), frames(%zu)",
+ type, ss->rate, ss->channels, format, processor->process_frames);
return NULL;
}
+ process_framesize = audio_effect_get_process_framesize(processor->audio_effect);
+
+ if (process_framesize > 0) {
+ processor->process_frames = process_framesize;
+ processor->process_usec = pa_processor_frame_to_usec(processor->process_frames, ss);
+ processor->process_bytes = pa_usec_to_bytes(processor->process_usec, ss);
+
+ pa_log_info("Changed process_frame. constraint process_frame(%zu)", processor->process_frames);
+ }
+
pa_silence_memchunk_get(&core->silence_cache, core->mempool, &silence, &processor->ss, 0);
processor->result_memblockq = pa_memblockq_new("source-output memblockq",
0,
}
void pa_processor_free(pa_processor *processor) {
-
pa_assert(processor);
- pa_assert(processor->priv);
- pa_assert(processor->interface);
+ pa_assert(processor->audio_effect);
- if (processor->interface->destroy(processor->priv) < 0)
- pa_log_error("Failed to destroy processor");
+ audio_effect_destroy(processor->audio_effect);
if (processor->result_memblockq)
pa_memblockq_free(processor->result_memblockq);
if (processor->reference)
pa_processor_reference_free(processor->reference);
- pa_xfree(processor->interface);
-
debug_close_file(processor);
pa_xfree(processor);
pa_assert(processor);
pa_assert(processor->result_memblockq);
- pa_assert(processor->interface);
pa_assert(processor->process_bytes > 0ULL);
pa_assert(chunk);
debug_timestamp_begin(processor);
- r = processor->interface->process(processor->priv, recording, reference, output);
+ r = audio_effect_process_reference(processor->audio_effect, recording, reference, output);
if (r < 0) {
pa_log_warn("Failed to process memchunk");
goto fail;
pa_memblock_unref(ochunk.memblock);
- return -1;
+ return r;
}
pa_memblockq *pa_processor_get_result_memblockq(pa_processor *processor) {
return method_table[method];
}
-pa_processor_method_t pa_processor_method_enum(const char *method) {
- pa_processor_method_t m;
+int pa_processor_method_enum(const char *method, pa_processor_method_t *m) {
+ pa_assert(method);
+ pa_assert(m);
if (pa_streq(method, "speex"))
- m = PROCESSOR_METHOD_SPEEX;
+ *m = PROCESSOR_METHOD_SPEEX;
else if (pa_streq(method, "webrtc"))
- m = PROCESSOR_METHOD_WEBRTC;
+ *m = PROCESSOR_METHOD_WEBRTC;
else if (pa_streq(method, "reference_copy"))
- m = PROCESSOR_METHOD_REFERENCE_COPY;
+ *m = PROCESSOR_METHOD_REFERENCE_COPY;
else if (pa_streq(method, "rnnoise"))
- m = PROCESSOR_METHOD_RNNOISE;
+ *m = PROCESSOR_METHOD_RNNOISE;
+ else if (pa_streq(method, "pse"))
+ *m = PROCESSOR_METHOD_NONE_PSE;
else
- pa_assert(0);
+ return -1;
- return m;
+ return 0;
}
bool pa_processor_method_need_reference_structure(pa_processor_method_t m) {
#include <pulse/channelmap.h>
#include <pulse/sample.h>
+#include <audio_effect.h>
#include "processor_reference.h"
#include "method_factory.h"
pa_sample_spec ss;
pa_memblockq *result_memblockq;
- void *priv;
- pa_processor_method *interface;
+ audio_effect_s *audio_effect;
pa_processor_method_t method;
pa_processor_reference *reference;
void pa_processor_attach_reference(pa_processor *processor, pa_processor_reference *reference);
pa_processor_reference *pa_processor_get_reference(pa_processor *processor);
-pa_processor_method_t pa_processor_method_enum(const char *method);
+int pa_processor_method_enum(const char *method, pa_processor_method_t *m);
const char *pa_processor_method_str(pa_processor_method_t method);
bool pa_processor_method_need_reference_structure(pa_processor_method_t m);
#define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
-pa_processor_holder *pa_processor_holder_new(pa_sample_spec *ss) {
+pa_processor_holder *pa_processor_holder_new(pa_core *core, pa_sample_spec *ss) {
pa_processor_holder *holder;
+ pa_memchunk silence;
pa_assert(ss);
holder = pa_xnew0(pa_processor_holder, 1);
holder->processors = pa_idxset_new(NULL, NULL);
+ pa_silence_memchunk_get(&core->silence_cache, core->mempool, &silence, ss, 0);
holder->input= pa_memblockq_new("holder input memblockq",
0,
MEMBLOCKQ_MAXLENGTH,
0,
0,
0,
- NULL);
+ &silence);
holder->output = pa_memblockq_new("holder output memblockq",
0,
0,
0,
0,
- NULL);
+ &silence);
+
+ pa_memblock_unref(silence.memblock);
return holder;
}
pa_memchunk chunk;
pa_processor *p;
int ret;
- size_t size;
uint32_t idx;
+ size_t length;
+ size_t process_size;
+
pa_assert(holder);
pull_queue = holder->input;
PA_IDXSET_FOREACH(p, holder->processors, idx) {
- if (pa_memblockq_peek(pull_queue, &chunk)) {
- pa_log_info("Failed to peek data. processor(%s)", pa_processor_method_str(p->method));
- return -1;
- }
+ process_size = pa_processor_get_process_bytes(p);
+ length = pa_memblockq_get_length(pull_queue);
- size = pa_processor_get_process_bytes(p);
- if (chunk.length < size) {
- pa_log_info("Not enough buffer. need to wait more buffer");
- pa_memblock_unref(chunk.memblock);
- return -1;
- }
+ if (length < process_size)
+ return -PROCESSOR_ERR_BUFFERING;
- /* chunk will be copied */
- /* TODO : ERROR BUFFERING */
- if ((ret = pa_processor_process(p, &chunk))) {
- if (ret == -2) {
- pa_log_info("Tried to process but processor has a latency");
- return 0;
- } else {
- pa_log_info("Failed to process");
- return 0;
+ while (length >= process_size) {
+ ret = pa_memblockq_peek_fixed_size(pull_queue, process_size, &chunk);
+ pa_assert(!ret);
+
+ if ((ret = pa_processor_process(p, &chunk)) < 0) {
+ pa_memblock_unref(chunk.memblock);
+ pa_memblockq_drop(pull_queue, chunk.length);
+ return ret;
}
- }
- pa_memblock_unref(chunk.memblock);
- pa_memblockq_drop(pull_queue, chunk.length);
+ pa_memblock_unref(chunk.memblock);
+ pa_memblockq_drop(pull_queue, chunk.length);
+
+ length = pa_memblockq_get_length(pull_queue);
+ }
pull_queue = pa_processor_get_result_memblockq(p);
}
- /* in case of only pass though */
- if (pull_queue == holder->input)
- return -1;
-
- pa_memblockq_peek(pull_queue, &chunk);
- pa_memblockq_push(holder->output, &chunk);
- pa_memblock_unref(chunk.memblock);
- pa_memblockq_drop(pull_queue, chunk.length);
+ length = pa_memblockq_get_length(pull_queue);
+ if (length > 0) {
+ pa_memblockq_peek_fixed_size(pull_queue, length, &chunk);
+ pa_memblockq_push(holder->output, &chunk);
+ pa_memblock_unref(chunk.memblock);
+ pa_memblockq_drop(pull_queue, chunk.length);
+ }
return 0;
}
#include <pulsecore/memblock.h>
#include <pulsecore/memchunk.h>
+#include "processor-def.h"
#include "processor.h"
typedef struct pa_processor_holder {
void *data2;
} pa_processor_holder;
-pa_processor_holder *pa_processor_holder_new(pa_sample_spec *ss);
+pa_processor_holder *pa_processor_holder_new(pa_core *core, pa_sample_spec *ss);
void pa_processor_holder_register_processor_sequencial(pa_processor_holder *holder, pa_processor *processor);
int pa_processor_holder_connect_reference(pa_processor_holder *holder, pa_processor_reference *reference);
int pa_processor_holder_push_data(pa_processor_holder *holder, pa_memchunk *chunk);
#include "hal-interface.h"
#include "tizenaudio-util.h"
-#include "preprocessor/preprocessor-def.h"
+#include "preprocessor/processor-def.h"
#include "preprocessor/processor_holder.h"
#include "preprocessor/processor_reference.h"
#include "hal-interface.h"
#include "tizenaudio-util.h"
-#include "preprocessor/preprocessor-def.h"
+#include "preprocessor/processor-def.h"
#include "preprocessor/processor_holder.h"
#define DEFAULT_SOURCE_NAME "tizenaudio-source2"