linuxOS_AP06/buildroot/package/alsa-plugins/0001-alsa-plugin-add-plugin-rockaa-on-init-version-v1.0.0.patch
2025-06-03 12:28:32 +08:00

1346 lines
37 KiB
Diff

From c644603414da7b274239cc9a0cffc76f63dfbcd4 Mon Sep 17 00:00:00 2001
From: Xing Zheng <zhengxing@rock-chips.com>
Date: Sun, 21 Apr 2024 09:27:31 +0800
Subject: [PATCH] alsa-plugin: add plugin rockaa on init version v1.0.0
Signed-off-by: Xing Zheng <zhengxing@rock-chips.com>
---
Makefile.am | 3 +
configure.ac | 12 +
rockaa/66-rockaa.conf | 62 +++
rockaa/Makefile.am | 21 +
rockaa/asound_example_rockaa.conf | 144 ++++++
rockaa/pcm_rockaa.c | 763 ++++++++++++++++++++++++++++++
rockaa/rockaa_capt.h | 66 +++
rockaa/rockaa_common.h | 124 +++++
rockaa/rockaa_play.h | 47 ++
9 files changed, 1242 insertions(+)
create mode 100644 rockaa/66-rockaa.conf
create mode 100644 rockaa/Makefile.am
create mode 100644 rockaa/asound_example_rockaa.conf
create mode 100644 rockaa/pcm_rockaa.c
create mode 100644 rockaa/rockaa_capt.h
create mode 100644 rockaa/rockaa_common.h
create mode 100644 rockaa/rockaa_play.h
diff --git a/Makefile.am b/Makefile.am
index af0e9c4..f69a3c1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,9 @@ endif
if HAVE_AAF
SUBDIRS += aaf
endif
+if HAVE_ROCKAA
+SUBDIRS += rockaa
+endif
EXTRA_DIST = gitcompile version COPYING.GPL m4/attributes.m4
AUTOMAKE_OPTIONS = foreign
diff --git a/configure.ac b/configure.ac
index 3215b96..a6fb152 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,16 @@ if test "x$enable_aaf" != "xno"; then
fi
AM_CONDITIONAL(HAVE_AAF, test x$HAVE_AAF = xyes)
+AC_ARG_ENABLE([rockaa],
+ AS_HELP_STRING([--disable-rockaa], [Disable building of RockAA plugin]))
+
+if test "x$enable_rockaa" != "xno"; then
+ PKG_CHECK_MODULES(rockaa, [rockaa], [HAVE_ROCKAA=yes], [HAVE_ROCKAA=no])
+fi
+AS_IF([test "x$enable_rockaa" != "xno"],
+ [AM_CONDITIONAL(HAVE_ROCKAA, true)],
+ [AM_CONDITIONAL(HAVE_ROCKAA, false)])
+
dnl ALSA plugin directory
AC_ARG_WITH(plugindir,
AS_HELP_STRING([--with-plugindir=dir],
@@ -266,6 +276,7 @@ AC_OUTPUT([
speex/Makefile
arcam-av/Makefile
aaf/Makefile
+ rockaa/Makefile
])
dnl Show the build conditions
@@ -305,3 +316,4 @@ if test "$HAVE_SPEEX" = "yes"; then
echo " speexdsp_LIBS: $speexdsp_LIBS"
fi
echo "AAF plugin: $HAVE_AAF"
+echo "RockAA plugin: $HAVE_ROCKAA"
diff --git a/rockaa/66-rockaa.conf b/rockaa/66-rockaa.conf
new file mode 100644
index 0000000..66ead26
--- /dev/null
+++ b/rockaa/66-rockaa.conf
@@ -0,0 +1,62 @@
+pcm.rockaa {
+ @args [ SLAVE RATE CAPT_CH_FAR CONF_PLAY_NAME CONF_CAPT_NAME
+ PLAY_IN PLAY_OUT CAPT_IN CAPT_OUT DEBUG_MODE ]
+ @args.SLAVE {
+ type string
+ default "plug:hw"
+ }
+ @args.RATE {
+ type integer
+ default 48000
+ }
+ @args.CAPT_CH_FAR {
+ type integer
+ default 0
+ }
+ @args.CONF_PLAY_NAME {
+ type string
+ default null
+ }
+ @args.CONF_CAPT_NAME {
+ type string
+ default null
+ }
+ @args.PLAY_IN {
+ type string
+ default null
+ }
+ @args.PLAY_OUT {
+ type string
+ default null
+ }
+ @args.CAPT_IN {
+ type string
+ default null
+ }
+ @args.CAPT_OUT {
+ type string
+ default null
+ }
+ @args.DEBUG_MODE {
+ type integer
+ default 0
+ }
+ type rockaa
+ slave.pcm $SLAVE
+ rate $RATE
+ capt_ch_far $CAPT_CH_FAR
+ conf_play_name $CONF_PLAY_NAME
+ conf_capt_name $CONF_CAPT_NAME
+ play_in $PLAY_IN
+ play_out $PLAY_OUT
+ capt_in $CAPT_IN
+ capt_out $CAPT_OUT
+ debug_mode $DEBUG_MODE
+ hint {
+ show {
+ @func refer
+ name defaults.namehint.basic
+ }
+ description "Plugin using RockkAA (Rockchip Audio Algorithm)"
+ }
+}
diff --git a/rockaa/Makefile.am b/rockaa/Makefile.am
new file mode 100644
index 0000000..aa497f4
--- /dev/null
+++ b/rockaa/Makefile.am
@@ -0,0 +1,21 @@
+GCONF_FILES = 66-rockaa.conf
+
+EXTRA_DIST = $(GCONF_FILES)
+
+asound_module_pcm_rockaa_LTLIBRARIES = libasound_module_pcm_rockaa.la
+asound_module_gconf_DATA = $(GCONF_FILES)
+
+asound_module_pcm_rockaadir = @ALSA_PLUGIN_DIR@
+asound_module_gconfdir = @ALSA_GCONF_DIR@
+
+AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @rockaa_CFLAGS@
+AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED)
+
+libasound_module_pcm_rockaa_la_SOURCES = pcm_rockaa.c
+libasound_module_pcm_rockaa_la_LIBADD = @ALSA_LIBS@ @rockaa_LIBS@ -lrockaa
+
+include ../install-hooks.am
+
+install-data-hook: install-conf-hook
+
+uninstall-local: uninstall-conf-hook
diff --git a/rockaa/asound_example_rockaa.conf b/rockaa/asound_example_rockaa.conf
new file mode 100644
index 0000000..de1ad60
--- /dev/null
+++ b/rockaa/asound_example_rockaa.conf
@@ -0,0 +1,144 @@
+# Copyright (c) 2024 Rockchip Electronics Co. Ltd.
+# Author: Xing Zheng <zhengxing@rock-chips.com>
+
+defaults.pcm.rate_converter "speexrate_medium"
+
+pcm.!default
+{
+ type asym
+ playback.pcm "rockaa_play_0"
+ capture.pcm "rockaa_capt_0"
+}
+
+# To user
+pcm.rockaa_play_0 {
+ type plug
+ slave {
+ pcm "rockaa_play_effect_0"
+ channels 2
+ format S16_LE
+ rate 48000
+ }
+}
+
+pcm.rockaa_play_1 {
+ type plug
+ slave {
+ pcm "rockaa_play_effect_1"
+ channels 2
+ format S16_LE
+ rate 48000
+ }
+}
+
+pcm.rockaa_capt_0 {
+ type softvol
+ slave.pcm "rockaa_capt_effect_0"
+ control {
+ name "Master RockAA Capture 0"
+ card 0
+ device 0
+ }
+ min_dB -50.0
+ max_dB 0.0
+ resolution 101
+}
+
+pcm.rockaa_capt_1 {
+ type softvol
+ slave.pcm "rockaa_capt_effect_1"
+ control {
+ name "Master RockAA Capture 1"
+ card 0
+ device 0
+ }
+ min_dB -50.0
+ max_dB 0.0
+ resolution 101
+}
+
+# To Rockaa and other plugins
+pcm.rockaa_play_effect_0 {
+ type rockaa
+ slave.pcm "softvol_rockaa_play"
+ conf_play_name /userdata/cfg/rockaa_conf/rkaudio_effect_eqdrc_48000hz_2ch_n48db.bin
+ debug_mode 0
+ # play_in /tmp/dbg_dump_playin.pcm
+ # play_out /tmp/dbg_dump_playout.pcm
+}
+
+pcm.rockaa_play_effect_1 {
+ type rockaa
+ slave.pcm "softvol_rockaa_play"
+ conf_play_name /userdata/cfg/rockaa_conf/rkaudio_effect_eqdrc_48000hz_2ch.bin
+ debug_mode 0
+ # play_in /tmp/dbg_dump_playin.pcm
+ # play_out /tmp/dbg_dump_playout.pcm
+}
+
+pcm.rockaa_capt_effect_0 {
+ type rockaa
+ slave.pcm "dsnooper"
+ conf_capt_name /userdata/cfg/rockaa_conf/config_aivqe.json
+ capt_ch_far 1
+ debug_mode 0
+ # capt_in /tmp/dbg_dump_capin.pcm
+ # capt_out /tmp/dbg_dump_capout.pcm
+}
+
+pcm.rockaa_capt_effect_1 {
+ type rockaa
+ slave.pcm "dsnooper"
+ conf_capt_name /userdata/cfg/rockaa_conf/config_aivqe_effect_1.json
+ capt_ch_far 1
+ debug_mode 0
+ # capt_in /tmp/dbg_dump_capin.pcm
+ # capt_out /tmp/dbg_dump_capout.pcm
+}
+
+pcm.softvol_rockaa_play {
+ type softvol
+ slave.pcm "dmixer"
+ control {
+ name "Master RockAA Playback"
+ card 0
+ device 0
+ }
+ min_dB -50.0
+ max_dB 0.0
+ resolution 101
+}
+
+# To Hardware
+pcm.dmixer {
+ type dmix
+ ipc_key 5978293 # must be unique for all dmix plugins!!!!
+ ipc_key_add_uid yes
+ slave {
+ pcm "hw:0,0,0"
+ channels 2
+ period_size 768
+ buffer_size 3072
+ }
+ bindings {
+ 0 0
+ 1 1
+ }
+}
+
+pcm.dsnooper {
+ type dsnoop
+ ipc_key 5978291 # must be unique for all dmix plugins!!!!
+ ipc_key_add_uid yes
+ slave {
+ pcm "hw:0,0,0"
+ channels 2
+ period_size 768
+ buffer_size 3072
+ }
+ bindings {
+ 0 0
+ 1 1
+ }
+}
+
diff --git a/rockaa/pcm_rockaa.c b/rockaa/pcm_rockaa.c
new file mode 100644
index 0000000..0cc83d5
--- /dev/null
+++ b/rockaa/pcm_rockaa.c
@@ -0,0 +1,763 @@
+/*
+ * Automatic alsa rockaa plugin
+ *
+ * Copyright (c) 2024 by Xing Zheng <zhengxing@rock-chips.com>
+ *
+ * This library 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.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <alsa/asoundlib.h>
+#include <alsa/pcm_external.h>
+
+#include "rockaa_capt.h"
+#include "rockaa_play.h"
+
+/** Force align frame size, the same with local version of alsa-lib/include/pcm.h */
+#define SND_PCM_FORCE_ALIGN_FRAME 0x00100000
+
+struct snd_pcm_rockaa
+{
+ snd_pcm_extplug_t ext; /* For pointer must be first member */
+ rockaa_p *hdl_p;
+ rockaa_c *hdl_c;
+ char setup_time[32];
+};
+
+typedef struct snd_pcm_rockaa snd_pcm_rockaa_t;
+
+static inline void *area_addr(const snd_pcm_channel_area_t *area,
+ snd_pcm_uframes_t offset)
+{
+ unsigned int bitofs = area->first + area->step * offset;
+ return (char *) area->addr + bitofs / 8;
+}
+
+static int rockaa_setup_time(struct snd_pcm_rockaa *rockaa)
+{
+ time_t now;
+ struct tm *local;
+
+ time(&now);
+ local = localtime(&now);
+
+ strftime(rockaa->setup_time, sizeof(rockaa->setup_time), "%Y%m%d%H%M%S", local);
+ LOGI("This RockAA setup time is: %s\n", rockaa->setup_time);
+ return 0;
+}
+
+/* NOTE: needs free realloc dump name outside */
+static int rockaa_realloc_dump(struct snd_pcm_rockaa *rockaa, char **dump_name)
+{
+ char *strbak = NULL, *strpre = NULL, *ptr = NULL;
+ int buflen = 0;
+
+ if (!dump_name || !(*dump_name))
+ {
+ LOGE("Invalid dump_name\n");
+ return -1;
+ }
+
+ strbak = strdup(*dump_name);
+ buflen = strlen(strbak) + strlen("_") + strlen(rockaa->setup_time);
+ LOGE("buflen=%d\n", buflen);
+ /**
+ * FIXME: Using calloc or memset will be crashed:
+ * free(): invalid next size (fast)
+ * or:
+ * malloc(): invalid size (unsorted)
+ */
+ // *dump_name = calloc(1, buflen);
+ *dump_name = malloc(buflen);
+ // memset((char *)(*dump_name), 0, buflen);
+ if (!(*dump_name))
+ {
+ LOGE("dump_name alloc faileld: errno=%d\n", errno);
+ }
+
+ strpre = strtok_r(strbak, ".", &ptr);
+ strcpy(*dump_name, strpre);
+ strcat(*dump_name, "_");
+ strcat(*dump_name, rockaa->setup_time);
+ strcat(*dump_name, ".pcm");
+ free(strbak);
+ return 0;
+}
+
+static snd_pcm_sframes_t
+rockaa_transfer(snd_pcm_extplug_t *ext,
+ const snd_pcm_channel_area_t *dst_areas,
+ snd_pcm_uframes_t dst_offset,
+ const snd_pcm_channel_area_t *src_areas,
+ snd_pcm_uframes_t src_offset,
+ snd_pcm_uframes_t size)
+{
+ struct snd_pcm_rockaa *rockaa = (struct snd_pcm_rockaa *)ext;
+ short *src = (short *)area_addr(src_areas, src_offset);
+ short *dst = (short *)area_addr(dst_areas, dst_offset);
+ int err = 0;
+
+ LOGV("%s: stream=%d src_offset=%ld dst_offset=%ld size=%ld\n",
+ __func__, ext->stream, src_offset, dst_offset, size);
+
+ if (ext->stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ if (rockaa->hdl_p->in_fp)
+ {
+ fwrite(src, 1,
+ rockaa->hdl_p->nb_samples * sizeof(short) * rockaa->hdl_p->channels,
+ rockaa->hdl_p->in_fp);
+ }
+
+ err = rockaa_play_effect_process(rockaa->hdl_p, src, dst);
+ if (err < 0)
+ {
+ SNDERR("rockaa playback effect failed: %d\n", err);
+ return err;
+ }
+
+ if (rockaa->hdl_p->out_fp)
+ {
+ fwrite(dst, 1,
+ rockaa->hdl_p->nb_samples * sizeof(short) * rockaa->hdl_p->channels,
+ rockaa->hdl_p->out_fp);
+ }
+ }
+ else if (ext->stream == SND_PCM_STREAM_CAPTURE)
+ {
+ if (rockaa->hdl_c->in_fp)
+ {
+ fwrite(src, 1,
+ rockaa->hdl_c->nb_samples * sizeof(short) * rockaa->hdl_c->channels,
+ rockaa->hdl_c->in_fp);
+ }
+
+ if (rockaa->hdl_c->out_buf)
+ {
+ short *out_buf = (short *)rockaa->hdl_c->out_buf;
+ int ch_out = rockaa->hdl_c->ch_out;
+ int nb_samples = rockaa->hdl_c->nb_samples;
+ int c, n;
+
+ err = rockaa_capt_effect_process(rockaa->hdl_c, src, out_buf);
+ if (err < 0)
+ {
+ SNDERR("rockaa capture effect failed: %d\n", err);
+ return err;
+ }
+
+ /* FIXME: copy mono to source channels */
+ for (n = 0; n < nb_samples; n++)
+ {
+ for (c = 0; c < rockaa->hdl_c->channels; c++)
+ {
+ *(dst + n * rockaa->hdl_c->channels + c) = *(out_buf + n * ch_out);
+ }
+ }
+ }
+ else
+ {
+ /* effect process bypass directly */
+ err = rockaa_capt_effect_process(rockaa->hdl_c, src, dst);
+ if (err < 0)
+ {
+ SNDERR("rockaa capture effect failed: %d\n", err);
+ return err;
+ }
+ }
+
+ /* TO DEBUG: */
+ // memcpy(dst, src, size * sizeof(short) * rockaa->hdl_c->channels);
+
+ if (rockaa->hdl_c->out_fp)
+ {
+ fwrite(dst, 1,
+ rockaa->hdl_c->nb_samples * sizeof(short) * rockaa->hdl_c->channels,
+ rockaa->hdl_c->out_fp);
+ }
+ }
+ else
+ {
+ SNDERR("Invalid stream: %d\n", ext->stream);
+ }
+
+ return size;
+}
+
+static int rockaa_init(snd_pcm_extplug_t *ext)
+{
+ return 0;
+}
+
+static int rockaa_close(snd_pcm_extplug_t *ext)
+{
+ struct snd_pcm_rockaa *rockaa = (struct snd_pcm_rockaa *)ext;
+
+ if (ext->stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ if (rockaa->hdl_p)
+ {
+ rockaa_play_effect_destroy(rockaa->hdl_p);
+
+ if (rockaa->hdl_p->conf_path)
+ {
+ free(rockaa->hdl_p->conf_path);
+ rockaa->hdl_p->conf_path = NULL;
+ }
+
+ if (rockaa->hdl_p->in_buf)
+ {
+ free(rockaa->hdl_p->in_buf);
+ rockaa->hdl_p->in_buf = NULL;
+ }
+
+ if (rockaa->hdl_p->out_buf)
+ {
+ free(rockaa->hdl_p->out_buf);
+ rockaa->hdl_p->out_buf = NULL;
+ }
+
+ if (rockaa->hdl_p->in_fp)
+ {
+ fclose(rockaa->hdl_p->in_fp);
+ rockaa->hdl_p->in_fp = NULL;
+ }
+
+ if (rockaa->hdl_p->out_fp)
+ {
+ fclose(rockaa->hdl_p->out_fp);
+ rockaa->hdl_p->out_fp = NULL;
+ }
+ free(rockaa->hdl_p);
+ rockaa->hdl_p = NULL;
+ }
+ }
+ else if (ext->stream == SND_PCM_STREAM_CAPTURE)
+ {
+ if (rockaa->hdl_c)
+ {
+ rockaa_capt_effect_destroy(rockaa->hdl_c);
+
+ if (rockaa->hdl_c->conf_path)
+ {
+ free(rockaa->hdl_c->conf_path);
+ rockaa->hdl_c->conf_path = NULL;
+ }
+
+ if (rockaa->hdl_c->in_buf)
+ {
+ free(rockaa->hdl_c->in_buf);
+ rockaa->hdl_c->in_buf = NULL;
+ }
+
+ if (rockaa->hdl_c->out_buf)
+ {
+ free(rockaa->hdl_c->out_buf);
+ rockaa->hdl_c->out_buf = NULL;
+ }
+
+ if (rockaa->hdl_c->in_fp)
+ {
+ fclose(rockaa->hdl_c->in_fp);
+ rockaa->hdl_c->in_fp = NULL;
+ }
+
+ if (rockaa->hdl_c->out_fp)
+ {
+ fclose(rockaa->hdl_c->out_fp);
+ rockaa->hdl_c->out_fp = NULL;
+ }
+ free(rockaa->hdl_c);
+ rockaa->hdl_c = NULL;
+ }
+ }
+ else
+ {
+ SNDERR("Invalid stream: %d\n", ext->stream);
+ }
+
+ return 0;
+}
+
+static int rockaa_hw_params(snd_pcm_extplug_t *ext, snd_pcm_hw_params_t *params)
+{
+ struct snd_pcm_rockaa *rockaa = (struct snd_pcm_rockaa *)ext;
+ snd_pcm_uframes_t period_size;
+ unsigned int rate, channels;
+ int err;
+
+ if (!ext)
+ {
+ SNDERR("ext plugin is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!params)
+ {
+ SNDERR("params is NULL\n");
+ return -EINVAL;
+ }
+
+ snd_pcm_hw_params_get_period_size(params, &period_size, 0);
+ snd_pcm_hw_params_get_rate(params, &rate, 0);
+ snd_pcm_hw_params_get_channels(params, &channels);
+ snd_pcm_hw_params_set_period_size_near(ext->pcm, params,
+ &period_size, 0);
+
+ if (ext->stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ if (!rockaa->hdl_p)
+ {
+ SNDERR("rockaa playback handle is NULL\n");
+ return -EINVAL;
+ }
+
+ rockaa->hdl_p->rate = rate;
+ rockaa->hdl_p->channels = channels;
+ rockaa->hdl_p->nb_samples = period_size;
+ LOGI("rockaa play: rate=%d channels=%d nb_samples=%d debug_mode=%d conf_path: %s\n",
+ rockaa->hdl_p->rate,
+ rockaa->hdl_p->channels,
+ rockaa->hdl_p->nb_samples,
+ rockaa->hdl_p->debug_mode,
+ rockaa->hdl_p->conf_path);
+
+ err = rockaa_play_effect_create(rockaa->hdl_p);
+ if (err < 0)
+ {
+ SNDERR("rockaa playback create failed: %d\n", err);
+ return err;
+ }
+ SNDERR("rockaa playback create success\n");
+ }
+ else if (ext->stream == SND_PCM_STREAM_CAPTURE)
+ {
+ if (!rockaa->hdl_c)
+ {
+ SNDERR("rockaa capture handle is NULL\n");
+ return -EINVAL;
+ }
+
+ rockaa->hdl_c->rate = rate;
+ rockaa->hdl_c->channels = channels;
+ rockaa->hdl_c->ch_near = channels - rockaa->hdl_c->ch_far;
+ rockaa->hdl_c->nb_samples = period_size;
+
+ LOGI("rockaa capt: rate=%d channels=%d(%d+%d) nb_samples=%d debug_mode=%d conf_path: %s\n",
+ rockaa->hdl_c->rate,
+ rockaa->hdl_c->channels, rockaa->hdl_c->ch_near, rockaa->hdl_c->ch_far,
+ rockaa->hdl_c->nb_samples,
+ rockaa->hdl_c->debug_mode,
+ rockaa->hdl_c->conf_path);
+ err = rockaa_capt_effect_create(rockaa->hdl_c);
+ if (err < 0)
+ {
+ SNDERR("rockaa capture create failed: %d\n", err);
+ return err;
+ }
+ SNDERR("rockaa capture create success, ch_out=%d\n", rockaa->hdl_c->ch_out);
+ if (rockaa->hdl_c->ch_out == 1)
+ {
+ rockaa->hdl_c->out_bytes = sizeof(short) * period_size * rockaa->hdl_c->ch_out;
+ rockaa->hdl_c->out_buf = (char *)malloc(rockaa->hdl_c->out_bytes);
+ if (!rockaa->hdl_c->out_buf)
+ {
+ SNDERR("Unable to allocate out_buf\n");
+ return -ENOMEM;
+ }
+ }
+ }
+ else
+ {
+ SNDERR("Invalid stream: %d\n", ext->stream);
+ }
+
+ return 0;
+}
+
+static int rockaa_hw_free(snd_pcm_extplug_t *ext)
+{
+ return 0;
+}
+
+#if SND_PCM_EXTPLUG_VERSION >= 0x10002
+static snd_pcm_chmap_query_t **rockaa_query_chmaps(snd_pcm_extplug_t *ext ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+static snd_pcm_chmap_t *rockaa_get_chmap(snd_pcm_extplug_t *ext)
+{
+ return NULL;
+}
+#endif /* SND_PCM_EXTPLUG_VERSION >= 0x10002 */
+
+static const snd_pcm_extplug_callback_t rockaa_callback =
+{
+ .transfer = rockaa_transfer,
+ .init = rockaa_init,
+ .close = rockaa_close,
+ .hw_params = rockaa_hw_params,
+ .hw_free = rockaa_hw_free,
+#if SND_PCM_EXTPLUG_VERSION >= 0x10002
+ .query_chmaps = rockaa_query_chmaps,
+ .get_chmap = rockaa_get_chmap,
+#endif
+};
+
+SND_PCM_PLUGIN_DEFINE_FUNC(rockaa)
+{
+ snd_config_iterator_t i, next;
+ snd_pcm_rockaa_t *rockaa;
+ snd_config_t *sconf = NULL;
+ const char *conf_play_name = NULL;
+ const char *conf_capt_name = NULL;
+ const char *play_in_name = NULL, *play_out_name = NULL;
+ const char *capt_in_name = NULL, *capt_out_name = NULL;
+ long channels = 2, rate = 48000, debug_mode = 0;
+ long ch_far = 0, enable_doa = 0;
+ unsigned int bit_format;
+ int err;
+
+ snd_config_for_each(i, next, conf)
+ {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id;
+ if (snd_config_get_id(n, &id) < 0)
+ continue;
+ if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0)
+ continue;
+ if (strcmp(id, "slave") == 0)
+ {
+ sconf = n;
+ continue;
+ }
+ if (strcmp(id, "rate") == 0)
+ {
+ snd_config_get_integer(n, &rate);
+ continue;
+ }
+ if (strcmp(id, "debug_mode") == 0)
+ {
+ long val;
+ err = snd_config_get_integer(n, &val);
+ if (err < 0)
+ {
+ SNDERR("Invalid value for %s", id);
+ return err;
+ }
+ debug_mode = val;
+ continue;
+ }
+ if (strcmp(id, "channels") == 0)
+ {
+ long val;
+ err = snd_config_get_integer(n, &val);
+ if (err < 0)
+ {
+ SNDERR("Invalid value for %s", id);
+ return err;
+ }
+ channels = val;
+ if (channels > 2)
+ {
+ SNDERR("channels must be 1 or 2");
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (strcmp(id, "capt_ch_far") == 0)
+ {
+ long val;
+ err = snd_config_get_integer(n, &val);
+ if (err < 0)
+ {
+ SNDERR("Invalid value for %s", id);
+ return err;
+ }
+ ch_far = val;
+ continue;
+ }
+ if (strcmp(id, "conf_play_name") == 0)
+ {
+ if ((err = snd_config_get_string(n, &conf_play_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (conf_play_name && (strcasecmp(conf_play_name, "null") == 0))
+ {
+ conf_play_name = NULL;
+ }
+ continue;
+ }
+ if (strcmp(id, "conf_capt_name") == 0)
+ {
+ if ((err = snd_config_get_string(n, &conf_capt_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (conf_capt_name && (strcasecmp(conf_capt_name, "null") == 0))
+ {
+ conf_capt_name = NULL;
+ }
+ continue;
+ }
+ if (strcmp(id, "play_in") == 0)
+ {
+ if ((err = snd_config_get_string(n, &play_in_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (play_in_name && (strcasecmp(play_in_name, "null") == 0))
+ {
+ play_in_name = NULL;
+ }
+ continue;
+ }
+ if (strcmp(id, "play_out") == 0)
+ {
+ if ((err = snd_config_get_string(n, &play_out_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (play_out_name && (strcasecmp(play_out_name, "null") == 0))
+ {
+ play_out_name = NULL;
+ }
+ continue;
+ }
+ if (strcmp(id, "capt_in") == 0)
+ {
+ if ((err = snd_config_get_string(n, &capt_in_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (capt_in_name && (strcasecmp(capt_in_name, "null") == 0))
+ {
+ capt_in_name = NULL;
+ }
+ continue;
+ }
+ if (strcmp(id, "capt_out") == 0)
+ {
+ if ((err = snd_config_get_string(n, &capt_out_name)) < 0)
+ {
+ SNDERR("field %s is not a string", id);
+ return err;
+ }
+
+ if (capt_out_name && (strcasecmp(capt_out_name, "null") == 0))
+ {
+ capt_out_name = NULL;
+ }
+ continue;
+ }
+
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+
+ if (!sconf)
+ {
+ SNDERR("No slave configuration for filrrockaa pcm");
+ return -EINVAL;
+ }
+
+ rockaa = calloc(1, sizeof(*rockaa));
+ if (rockaa == NULL)
+ return -ENOMEM;
+
+ bit_format = SND_PCM_FORMAT_S16;
+
+ rockaa->ext.version = SND_PCM_EXTPLUG_VERSION;
+ rockaa->ext.name = "RockAA ALSA Plugin";
+ rockaa->ext.callback = &rockaa_callback;
+ rockaa->ext.private_data = rockaa;
+ rockaa->ext.rate = rate;
+ rockaa->ext.channels = channels;
+ rockaa->ext.slave_channels = channels;
+ rockaa->ext.format = bit_format;
+ rockaa->ext.slave_format = bit_format;
+ rockaa_setup_time(rockaa);
+
+ /* force sync and align frame size during capture */
+ mode |= SND_PCM_FORCE_ALIGN_FRAME;
+ err = snd_pcm_extplug_create(&rockaa->ext, name, root, sconf, stream, mode);
+ if (err < 0)
+ {
+ free(rockaa);
+ return err;
+ }
+
+ snd_pcm_extplug_set_param(&rockaa->ext, SND_PCM_EXTPLUG_HW_FORMAT,
+ bit_format);
+ snd_pcm_extplug_set_slave_param(&rockaa->ext, SND_PCM_EXTPLUG_HW_FORMAT,
+ bit_format);
+
+ snd_pcm_extplug_set_param_minmax(&rockaa->ext,
+ SND_PCM_EXTPLUG_HW_CHANNELS,
+ 1, channels);
+ snd_pcm_extplug_set_slave_param_minmax(&rockaa->ext,
+ SND_PCM_EXTPLUG_HW_CHANNELS,
+ 1, channels);
+
+ if (rockaa->ext.stream == SND_PCM_STREAM_PLAYBACK)
+ {
+ rockaa_p *hdl_p;
+
+ hdl_p = (rockaa_p *)calloc(1, sizeof(rockaa_p));
+ if (!hdl_p)
+ {
+ LOGE("alloc talk hdl_p failed\n");
+ return -1;
+ }
+
+ hdl_p->bits = bit_format | ROCKAA_ALSA_BIT_FORMAT;
+ hdl_p->debug_mode = debug_mode;
+ hdl_p->conf_path = conf_play_name ? (char *)strdup(conf_play_name) : NULL;
+
+ if (play_in_name)
+ {
+ const char *play_in_dump = play_in_name;
+
+ if (access(play_in_dump, F_OK) == 0)
+ {
+ rockaa_realloc_dump(rockaa, &play_in_dump);
+ }
+
+ hdl_p->in_fp = fopen(play_in_dump, "wb");
+ if (hdl_p->in_fp == NULL)
+ {
+ LOGE("%s play_in_name fopen failed\n", play_in_dump);
+ return -1;
+ }
+ LOGI("open play_in: %s success\n", play_in_dump);
+
+ if (play_in_dump && (play_in_dump != play_in_name))
+ {
+ free(play_in_dump);
+ play_in_dump = NULL;
+ }
+ }
+ if (play_out_name)
+ {
+ const char *play_out_dump = play_out_name;
+
+ if (access(play_out_dump, F_OK) == 0)
+ {
+ rockaa_realloc_dump(rockaa, &play_out_dump);
+ }
+
+ hdl_p->out_fp = fopen(play_out_dump, "wb");
+ if (hdl_p->out_fp == NULL)
+ {
+ LOGE("%s play_out_name fopen failed\n", play_out_dump);
+ return -1;
+ }
+ LOGI("open play_out: %s success\n", play_out_dump);
+
+ if (play_out_dump && (play_out_dump != play_out_name))
+ {
+ free(play_out_dump);
+ play_out_dump = NULL;
+ }
+ }
+
+ rockaa->hdl_p = hdl_p;
+ }
+ else if (rockaa->ext.stream == SND_PCM_STREAM_CAPTURE)
+ {
+ rockaa_c *hdl_c;
+
+ hdl_c = (rockaa_c *)calloc(1, sizeof(rockaa_c));
+ if (!hdl_c)
+ {
+ LOGE("alloc talk hdl_c failed\n");
+ return -1;
+ }
+
+ hdl_c->bits = bit_format | ROCKAA_ALSA_BIT_FORMAT;
+ hdl_c->ch_far = ch_far;
+ hdl_c->debug_mode = debug_mode;
+ hdl_c->enable_doa = enable_doa;
+ hdl_c->conf_path = conf_capt_name ? (char *)strdup(conf_capt_name) : NULL;
+
+ if (capt_in_name)
+ {
+ const char *capt_in_dump = capt_in_name;
+
+ if (access(capt_in_dump, F_OK) == 0)
+ {
+ rockaa_realloc_dump(rockaa, &capt_in_dump);
+ }
+
+ hdl_c->in_fp = fopen(capt_in_dump, "wb");
+ if (hdl_c->in_fp == NULL)
+ {
+ LOGE("%s capt_in_name fopen failed\n", capt_in_dump);
+ return -1;
+ }
+ LOGI("open capt_in: %s success\n", capt_in_dump);
+
+ if (capt_in_dump && (capt_in_dump != capt_in_name))
+ {
+ free(capt_in_dump);
+ capt_in_dump = NULL;
+ }
+ }
+ if (capt_out_name)
+ {
+ const char *capt_out_dump = capt_out_name;
+
+ if (access(capt_out_dump, F_OK) == 0)
+ {
+ rockaa_realloc_dump(rockaa, &capt_out_dump);
+ }
+ hdl_c->out_fp = fopen(capt_out_dump, "wb");
+ if (hdl_c->out_fp == NULL)
+ {
+ LOGE("%s capt_out_name fopen failed\n", capt_out_dump);
+ return -1;
+ }
+ LOGI("open capt_out: %s success\n", capt_out_dump);
+
+ if (capt_out_dump && (capt_out_dump != capt_out_name))
+ {
+ free(capt_out_dump);
+ capt_out_dump = NULL;
+ }
+ }
+
+ rockaa->hdl_c = hdl_c;
+ }
+ else
+ {
+ SNDERR("Invalid stream: %d\n", rockaa->ext.stream);
+ }
+
+ *pcmp = rockaa->ext.pcm;
+ return 0;
+}
+
+SND_PCM_PLUGIN_SYMBOL(rockaa);
diff --git a/rockaa/rockaa_capt.h b/rockaa/rockaa_capt.h
new file mode 100644
index 0000000..459e446
--- /dev/null
+++ b/rockaa/rockaa_capt.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ *
+ * Author: xing.zheng@rock-chips.com
+ * Date: 2023.02.28
+ */
+
+#ifndef __ROCKAA_CAPT_H__
+#define __ROCKAA_CAPT_H__
+
+#include "rockaa_common.h"
+
+enum
+{
+ STATUS_RES_SUCCESS = 0,
+ STATUS_RES_NONE = -1,
+ STATUS_RES_INVALID = -2,
+};
+
+typedef struct _result_capt
+{
+ int angle_horiz;
+ int angle_pitch;
+} result_capt;
+
+typedef struct _rockaa_c
+{
+ /* base members */
+ void *effect;
+ FILE *in_fp;
+ FILE *out_fp;
+ char *in_buf;
+ char *out_buf;
+ char *conf_path;
+ int out_bytes;
+ int rate;
+ int channels;
+ int bits;
+ int nb_samples;
+ /* customized members */
+ int debug_mode;
+ bool enable_doa;
+ int ch_near;
+ int ch_far;
+ int ch_out; /* ==1: BF is enabled, ==ch_near: BF is disabled, configured by rockaa_capt_effect_create() */
+ result_capt results;
+} rockaa_c;
+
+int rockaa_capt_effect_create(rockaa_c *handle);
+int rockaa_capt_effect_destroy(rockaa_c *handle);
+int rockaa_capt_effect_process(rockaa_c *handle, short *pcm_in, short *pcm_out);
+int rockaa_capt_effect_results(rockaa_c *handle);
+
+#endif /* __ROCKAA_CAPT_H__ */
diff --git a/rockaa/rockaa_common.h b/rockaa/rockaa_common.h
new file mode 100644
index 0000000..a001cc5
--- /dev/null
+++ b/rockaa/rockaa_common.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2023 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ *
+ * Author: xing.zheng@rock-chips.com
+ * Date: 2023.02.28
+ */
+
+#ifndef __ROCKAA_COMMON_H__
+#define __ROCKAA_COMMON_H__
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#define rt_memset memset
+#define rt_malloc(x) calloc(1, x)
+#define rt_safe_free(x) do { if (x) free(x); } while (0)
+#define RT_NULL NULL
+#define RT_NONE "none"
+#define RT_BOOL char
+#define RT_TRUE 1
+#define RT_FALSE 0
+
+#define RT_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+
+#define ROCKAA_VERSION "V1.1.0"
+#define DEFAULT_FRAME_GAP 16
+
+#define ROCKAA_ALSA_BIT_FORMAT 0x8000000
+
+typedef enum _alsa_snd_pcm_format_part {
+ ALSA_SND_PCM_FORMAT_S16 = 2,
+} alsa_snd_pcm_format_part;
+
+typedef int8_t INT8;
+typedef int16_t INT16;
+typedef int32_t INT32;
+typedef int64_t INT64;
+
+typedef uint8_t UINT8;
+typedef uint8_t UCHAR;
+typedef uint16_t UINT16;
+typedef uint32_t UINT32;
+typedef uint64_t UINT64;
+
+typedef void *RT_PTR;
+typedef void RT_VOID;
+typedef float RT_FLOAT;
+typedef short RT_SHORT;
+
+typedef enum _ROCKAA_DEBUG
+{
+ DEBUG_SUMMARY = 1 << 0,
+ DEBUG_PER_FRAME = 1 << 1,
+} ROCKAA_DEBUG;
+
+struct wav_header
+{
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+#define LOGV(format, ...) \
+ do { \
+ } while (0)
+
+#define LOGD(format, ...) \
+ do { \
+ fprintf(stderr, "[tagD] " format, ##__VA_ARGS__); \
+ if(format[strlen(format) - 1] != '\n') \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
+#define LOGI(format, ...) \
+ do { \
+ fprintf(stderr, "[tagI] " format, ##__VA_ARGS__); \
+ if(format[strlen(format) - 1] != '\n') \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
+#define LOGE(format, ...) \
+ do { \
+ fprintf(stderr, "[tagE] " format, ##__VA_ARGS__); \
+ if(format[strlen(format) - 1] != '\n') \
+ fprintf(stderr, "\n"); \
+ } while (0)
+
+#define RT_ASSERT assert
+
+inline static void rockaa_version(char *tag)
+{
+ printf("Test for Rock Audio Algorithm %s Version: %s\n",
+ tag, ROCKAA_VERSION);
+}
+
+int rockaa_common_handle_wav(FILE *in_fp, char *in_file);
+
+#endif /* __ROCKAA_COMMON_H__ */
diff --git a/rockaa/rockaa_play.h b/rockaa/rockaa_play.h
new file mode 100644
index 0000000..607deda
--- /dev/null
+++ b/rockaa/rockaa_play.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 Rockchip Electronics Co. LTD
+ *
+ * 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.
+ *
+ * Author: xing.zheng@rock-chips.com
+ * Date: 2023.03.30
+ */
+
+#ifndef __ROCKAA_PLAY_H__
+#define __ROCKAA_PLAY_H__
+
+#include "rockaa_common.h"
+
+typedef struct _rockaa_p
+{
+ /* base members */
+ void *effect;
+ FILE *in_fp;
+ FILE *out_fp;
+ char *in_buf;
+ char *out_buf;
+ char *conf_path;
+ int out_bytes;
+ int rate;
+ int channels;
+ int bits;
+ int nb_samples;
+ /* customized members */
+ int debug_mode;
+} rockaa_p;
+
+int rockaa_play_effect_create(rockaa_p *handle);
+int rockaa_play_effect_destroy(rockaa_p *handle);
+int rockaa_play_effect_process(rockaa_p *handle, short *pcm_in, short *pcm_out);
+
+#endif /* __ROCKAA_PLAY_H__ */
--
2.34.1