summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE.Apache-2.0202
-rw-r--r--Makefile.am21
-rw-r--r--NOTICE3
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac64
-rw-r--r--hal-backend-audio-alsa.manifest5
-rw-r--r--hal-backend-audio.c88
-rw-r--r--packaging/hal-backend-audio-alsa.spec52
-rw-r--r--tizen-audio-comm.c116
-rw-r--r--tizen-audio-ctrl.c46
-rw-r--r--tizen-audio-impl-ctrl.c254
-rw-r--r--tizen-audio-impl-pcm.c811
-rw-r--r--tizen-audio-impl.h47
-rw-r--r--tizen-audio-internal.h252
-rw-r--r--tizen-audio-pcm.c204
-rw-r--r--tizen-audio-routing.c294
-rw-r--r--tizen-audio-stream.c54
-rw-r--r--tizen-audio-util.c80
-rw-r--r--tizen-audio-volume.c452
-rw-r--r--tizen-audio.c90
-rw-r--r--tizen-audio.h431
21 files changed, 3576 insertions, 0 deletions
diff --git a/LICENSE.Apache-2.0 b/LICENSE.Apache-2.0
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.Apache-2.0
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6457672
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,21 @@
+lib_LTLIBRARIES = libhal-backend-audio.la
+
+libhal_backend_audio_la_SOURCES = tizen-audio.c \
+ tizen-audio-volume.c \
+ tizen-audio-routing.c \
+ tizen-audio-stream.c \
+ tizen-audio-pcm.c \
+ tizen-audio-util.c \
+ tizen-audio-comm.c \
+ tizen-audio-ctrl.c \
+ tizen-audio-impl-pcm.c \
+ tizen-audio-impl-ctrl.c \
+ hal-backend-audio.c
+libhal_backend_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
+libhal_backend_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS)
+libhal_backend_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) $(HALAPICOMMON) -DUSE_DLOG
+
+if USE_TINYALSA
+libhal_backend_audio_la_LIBADD += $(TINYALSA_LIBS)
+libhal_backend_audio_la_CFLAGS += $(TINYALSA_CFLAGS) -D__USE_TINYALSA__
+endif \ No newline at end of file
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..ccdad52
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE file for Apache License terms and conditions.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..8e229ef
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# autogen.sh -- Autotools bootstrapping
+#
+
+libtoolize --copy --force
+aclocal && \
+autoheader && \
+autoconf && \
+automake --add-missing --copy
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..06192cb
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,64 @@
+AC_PREREQ([2.67])
+
+AC_INIT([audio-alsa], [0.1])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_CONFIG_HEADERS([config.h])
+
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+m4_pattern_allow([AM_PROG_AR])
+AM_PROG_AR
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+
+PKG_CHECK_MODULES(ASOUNDLIB, alsa >= 1.0.24)
+AC_SUBST(ASOUNDLIB_CFLAGS)
+AC_SUBST(ASOUNDLIB_LIBS)
+
+if test $USE_TINYALSA = "1"; then
+PKG_CHECK_MODULES(TINYALSA, tinyalsa)
+AC_SUBST(TINYALSA_CFLAGS)
+AC_SUBST(TINYALSA_LIBS)
+AM_CONDITIONAL(USE_TINYALSA, true)
+else
+AM_CONDITIONAL(USE_TINYALSA, false)
+fi
+
+PKG_CHECK_MODULES(VCONF, vconf)
+AC_SUBST(VCONF_CFLAGS)
+AC_SUBST(VCONF_LIBS)
+
+PKG_CHECK_MODULES(INIPARSER, iniparser)
+AC_SUBST(INIPARSER_CFLAGS)
+AC_SUBST(INIPARSER_LIBS)
+
+PKG_CHECK_MODULES(DLOG, dlog)
+AC_SUBST(DLOG_CFLAGS)
+AC_SUBST(DLOG_LIBS)
+
+PKG_CHECK_MODULES(HALAPICOMMON, hal-api-common)
+AC_SUBST(HALAPICOMMON_CFLAGS)
+AC_SUBST(HALAPICOMMON_LIBS)
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+
+
+AC_CONFIG_FILES([ \
+ Makefile
+ ])
+AC_OUTPUT
diff --git a/hal-backend-audio-alsa.manifest b/hal-backend-audio-alsa.manifest
new file mode 100644
index 0000000..86dbb26
--- /dev/null
+++ b/hal-backend-audio-alsa.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
diff --git a/hal-backend-audio.c b/hal-backend-audio.c
new file mode 100644
index 0000000..42292f2
--- /dev/null
+++ b/hal-backend-audio.c
@@ -0,0 +1,88 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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 <stdint.h>
+#include <errno.h>
+#include <tizen-audio.h>
+#include <hal/hal-common-interface.h>
+
+static int audio_alsa_init(void **data)
+{
+ hal_backend_audio_funcs *funcs;
+
+ funcs = calloc(1, sizeof(hal_backend_audio_funcs));
+ if (!funcs)
+ return -ENOMEM;
+
+ funcs->init = audio_init;
+ funcs->deinit = audio_deinit;
+
+ funcs->get_volume_level_max = audio_get_volume_level_max;
+ funcs->get_volume_level = audio_get_volume_level;
+ funcs->set_volume_level = audio_set_volume_level;
+ funcs->get_volume_value = audio_get_volume_value;
+ funcs->get_volume_mute = audio_get_volume_mute;
+ funcs->set_volume_mute = audio_set_volume_mute;
+ funcs->set_volume_ratio = audio_set_volume_ratio;
+ funcs->notify_ducking_activation_changed = audio_notify_ducking_activation_changed;
+
+ funcs->update_route = audio_update_route;
+ funcs->update_route_option = audio_update_route_option;
+
+ funcs->notify_stream_connection_changed = audio_notify_stream_connection_changed;
+
+ funcs->pcm_open = audio_pcm_open;
+ funcs->pcm_start = audio_pcm_start;
+ funcs->pcm_stop = audio_pcm_stop;
+ funcs->pcm_close = audio_pcm_close;
+ funcs->pcm_avail = audio_pcm_avail;
+ funcs->pcm_write = audio_pcm_write;
+ funcs->pcm_read = audio_pcm_read;
+ funcs->pcm_get_fd = audio_pcm_get_fd;
+ funcs->pcm_recover = audio_pcm_recover;
+ funcs->pcm_get_params = audio_pcm_get_params;
+ funcs->pcm_set_params = audio_pcm_set_params;
+
+ funcs->add_message_cb = audio_add_message_cb;
+ funcs->remove_message_cb = audio_remove_message_cb;
+
+ *data = (void *)funcs;
+
+ return 0;
+}
+
+static int audio_alsa_exit(void *data)
+{
+ if (!data)
+ return -EINVAL;
+
+ free(data);
+
+ return 0;
+}
+
+hal_backend hal_backend_audio_data = {
+ .name = "audio-alsa",
+ .vendor = "Tizen",
+ .abi_version = HAL_ABI_VERSION_TIZEN_6_5,
+ .init = audio_alsa_init,
+ .exit = audio_alsa_exit,
+};
diff --git a/packaging/hal-backend-audio-alsa.spec b/packaging/hal-backend-audio-alsa.spec
new file mode 100644
index 0000000..c662617
--- /dev/null
+++ b/packaging/hal-backend-audio-alsa.spec
@@ -0,0 +1,52 @@
+Name: hal-backend-audio-alsa
+Summary: TIZEN Audio HAL using ALSA
+Version: 0.0.1
+Release: 0
+Group: System/Libraries
+License: Apache-2.0
+URL: http://tizen.org
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(iniparser)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(alsa)
+BuildRequires: pkgconfig(hal-api-common)
+BuildRequires: pkgconfig(hal-api-audio)
+#BuildRequires: pkgconfig(tinyalsa)
+Provides: libhal-backend-audio.so
+
+%description
+TIZEN Audio HAL using ALSA
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\""
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+
+export USE_TINYALSA="0"
+
+%autogen
+./configure --libdir=%{_hal_libdir}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}%{_hal_licensedir}/%{name}
+cp LICENSE.Apache-2.0 %{buildroot}%{_hal_licensedir}/%{name}
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%{_hal_libdir}/libhal-backend-audio.so
+%{_hal_licensedir}/%{name}/*
diff --git a/tizen-audio-comm.c b/tizen-audio-comm.c
new file mode 100644
index 0000000..ad9c8e5
--- /dev/null
+++ b/tizen-audio-comm.c
@@ -0,0 +1,116 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+static audio_return_e __set_message_callback(audio_hal_s *ah, message_cb callback, void *user_data)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+ ah->comm.msg_cb = callback;
+ ah->comm.user_data = user_data;
+
+ AUDIO_LOG_DEBUG("message callback is set, callback(%p), user_data(%p)", ah->comm.msg_cb, ah->comm.user_data);
+
+ return audio_ret;
+}
+
+static audio_return_e __unset_message_callback(audio_hal_s *ah)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->comm.msg_cb = NULL;
+ ah->comm.user_data = NULL;
+
+ AUDIO_LOG_DEBUG("message callback is unset");
+
+ return audio_ret;
+}
+
+audio_return_e _audio_comm_init(audio_hal_s *ah)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->comm.msg_cb = NULL;
+ ah->comm.user_data = NULL;
+
+ return audio_ret;
+}
+
+audio_return_e _audio_comm_deinit(audio_hal_s *ah)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->comm.msg_cb = NULL;
+ ah->comm.user_data = NULL;
+
+ return audio_ret;
+}
+
+audio_return_e _audio_comm_send_message(audio_hal_s *ah, const char *name, int value)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(name, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_DEBUG("send message : name(%s), value(%d)", name, value);
+ if (ah->comm.msg_cb)
+ ah->comm.msg_cb(name, value, ah->comm.user_data);
+
+ return audio_ret;
+}
+
+audio_return_e audio_add_message_cb(void *audio_handle, message_cb callback, void *user_data)
+{
+ audio_return_e ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+ /* NOTE: Management of several callbacks could be implemented.
+ But we do not care of it for now.*/
+ ret = __set_message_callback((audio_hal_s *)audio_handle, callback, user_data);
+
+ return ret;
+}
+
+audio_return_e audio_remove_message_cb(void *audio_handle, message_cb callback)
+{
+ audio_return_e ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+ ret = __unset_message_callback((audio_hal_s *)audio_handle);
+
+ return ret;
+}
diff --git a/tizen-audio-ctrl.c b/tizen-audio-ctrl.c
new file mode 100644
index 0000000..7158738
--- /dev/null
+++ b/tizen-audio-ctrl.c
@@ -0,0 +1,46 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+audio_return_e _audio_ctrl_init(audio_hal_s *ah)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _mixer_control_init(ah);
+
+ return audio_ret;
+}
+
+audio_return_e _audio_ctrl_deinit(audio_hal_s *ah)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _mixer_control_deinit(ah);
+
+ return audio_ret;
+}
diff --git a/tizen-audio-impl-ctrl.c b/tizen-audio-impl-ctrl.c
new file mode 100644
index 0000000..cf4b4ce
--- /dev/null
+++ b/tizen-audio-impl-ctrl.c
@@ -0,0 +1,254 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "tizen-audio-internal.h"
+
+#ifdef __MIXER_PARAM_DUMP
+static void __dump_mixer_param(char *dump, long *param, int size)
+{
+ int i, len;
+
+ for (i = 0; i < size; i++) {
+ len = sprintf(dump, "%ld", *param);
+ if (len > 0)
+ dump += len;
+ if (i != size -1)
+ *dump++ = ',';
+
+ param++;
+ }
+ *dump = '\0';
+}
+#endif
+
+audio_return_e _mixer_control_init(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_init(&(ah->mixer.mutex), NULL);
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _mixer_control_deinit(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_destroy(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _mixer_control_set_param(audio_hal_s *ah, const char* ctl_name, snd_ctl_elem_value_t* param, int size)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _mixer_control_get_value(audio_hal_s *ah, const char *card, const char *ctl_name, int *val)
+{
+ snd_ctl_t *handle;
+ snd_ctl_elem_value_t *control;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_type_t type;
+
+ int ret = 0, count = 0, i = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(val, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, card, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, %s\n", snd_strerror(ret));
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_IOCTL;
+ }
+
+ // Get Element Info
+
+ snd_ctl_elem_id_alloca(&id);
+ snd_ctl_elem_info_alloca(&info);
+ snd_ctl_elem_value_alloca(&control);
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl_name);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if (snd_ctl_elem_info(handle, info) < 0) {
+ AUDIO_LOG_ERROR("Cannot find control element: %s\n", ctl_name);
+ goto close;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ type = snd_ctl_elem_info_get_type(info);
+ count = snd_ctl_elem_info_get_count(info);
+
+ snd_ctl_elem_value_set_id(control, id);
+
+ if (snd_ctl_elem_read(handle, control) < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_elem_read failed \n");
+ goto close;
+}
+
+ switch (type) {
+ case SND_CTL_ELEM_TYPE_BOOLEAN:
+ *val = snd_ctl_elem_value_get_boolean(control, i);
+ break;
+ case SND_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < count; i++)
+ *val = snd_ctl_elem_value_get_integer(control, i);
+ break;
+ case SND_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < count; i++)
+ *val = snd_ctl_elem_value_get_enumerated(control, i);
+ break;
+ default:
+ AUDIO_LOG_WARN("unsupported control element type\n");
+ goto close;
+ }
+
+ snd_ctl_close(handle);
+
+#ifdef AUDIO_DEBUG
+ AUDIO_LOG_INFO("get mixer(%s) = %d success", ctl_name, *val);
+#endif
+
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR("Error\n");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_e _mixer_control_set_value(audio_hal_s *ah, const char *card, const char *ctl_name, int val)
+{
+ snd_ctl_t *handle;
+ snd_ctl_elem_value_t *control;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_type_t type;
+ int ret = 0, count = 0, i = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, card, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", card, snd_strerror(ret));
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_IOCTL;
+ }
+
+ // Get Element Info
+
+ snd_ctl_elem_id_alloca(&id);
+ snd_ctl_elem_info_alloca(&info);
+ snd_ctl_elem_value_alloca(&control);
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl_name);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if (snd_ctl_elem_info(handle, info) < 0) {
+ AUDIO_LOG_ERROR("Cannot find control element: %s", ctl_name);
+ goto close;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ type = snd_ctl_elem_info_get_type(info);
+ count = snd_ctl_elem_info_get_count(info);
+
+ snd_ctl_elem_value_set_id(control, id);
+
+ snd_ctl_elem_read(handle, control);
+
+ switch (type) {
+ case SND_CTL_ELEM_TYPE_BOOLEAN:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_boolean(control, i, val);
+ break;
+ case SND_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_integer(control, i, val);
+ break;
+ case SND_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_enumerated(control, i, val);
+ break;
+
+ default:
+ AUDIO_LOG_WARN("unsupported control element type");
+ goto close;
+ }
+
+ snd_ctl_elem_write(handle, control);
+
+ snd_ctl_close(handle);
+
+ AUDIO_LOG_INFO("set mixer(%s) = %d success", ctl_name, val);
+
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR("Error");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_e _mixer_control_set_value_string(audio_hal_s *ah, const char* ctl_name, const char* value)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+
+audio_return_e _mixer_control_get_element(audio_hal_s *ah, const char *ctl_name, snd_hctl_elem_t **elem)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(elem, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
diff --git a/tizen-audio-impl-pcm.c b/tizen-audio-impl-pcm.c
new file mode 100644
index 0000000..7e3f8d8
--- /dev/null
+++ b/tizen-audio-impl-pcm.c
@@ -0,0 +1,811 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+#ifndef __USE_TINYALSA__
+#define DEVICE_NAME_MAX 32
+#endif
+
+#ifdef __USE_TINYALSA__
+/* Convert pcm format from pulse to alsa */
+static const uint32_t g_format_convert_table[] = {
+ [AUDIO_SAMPLE_U8] = PCM_FORMAT_S8,
+ [AUDIO_SAMPLE_S16LE] = PCM_FORMAT_S16_LE,
+ [AUDIO_SAMPLE_S32LE] = PCM_FORMAT_S32_LE,
+ [AUDIO_SAMPLE_S24_32LE] = PCM_FORMAT_S24_LE
+};
+#else /* alsa-lib */
+/* FIXME : To avoid build warning... */
+int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
+/* Convert pcm format from pulse to alsa */
+static const uint32_t g_format_convert_table[] = {
+ [AUDIO_SAMPLE_U8] = SND_PCM_FORMAT_U8,
+ [AUDIO_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
+ [AUDIO_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
+ [AUDIO_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
+ [AUDIO_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
+ [AUDIO_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
+ [AUDIO_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
+ [AUDIO_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
+ [AUDIO_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
+ [AUDIO_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
+ [AUDIO_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
+ [AUDIO_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
+ [AUDIO_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE
+};
+#endif
+
+static uint32_t __convert_format(audio_sample_format_s format)
+{
+ return g_format_convert_table[format];
+}
+
+#ifdef __USE_TINYALSA__
+static int __parse_card_device_number(const char *card, const char *device, unsigned int *card_u, unsigned int *device_u) {
+ AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(card_u, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(device_u, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_DEBUG("card : %s, device : %s", card, device);
+
+ *card_u = (unsigned int) strtol(card, NULL, 10);
+ *device_u = (unsigned int) strtol(device, NULL, 10);
+
+ return 0;
+}
+
+static struct pcm *__tinyalsa_open_device(const char *card, const char *device, audio_pcm_sample_spec_s *ss, size_t period_size, size_t period_count, uint32_t direction)
+{
+ struct pcm *pcm = NULL;
+ struct pcm_config config;
+ unsigned int card_u, device_u;
+
+ AUDIO_RETURN_NULL_IF_FAIL(device);
+ AUDIO_RETURN_NULL_IF_FAIL(ss);
+
+ config.channels = ss->channels;
+ config.rate = ss->rate;
+ config.period_size = period_size;
+ config.period_count = period_count;
+ config.format = ss->format;
+ config.start_threshold = period_size;
+ config.stop_threshold = 0xFFFFFFFF;
+ config.silence_threshold = 0;
+
+ AUDIO_LOG_INFO("card %s, device %s, direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d",
+ card, device, direction, ss->channels, ss->rate, ss->format, period_size, period_count);
+
+ if (__parse_card_device_number(card, device, &card_u, &device_u) < 0) {
+ AUDIO_LOG_ERROR("Failed to get card device number from %s", device);
+ return NULL;
+ }
+
+ pcm = pcm_open(card_u, device_u, (direction == AUDIO_DIRECTION_OUT) ? PCM_OUT : PCM_IN, &config);
+ if (!pcm || !pcm_is_ready(pcm)) {
+ AUDIO_LOG_ERROR("Unable to open device (%s)", pcm_get_error(pcm));
+ pcm_close(pcm);
+ return NULL;
+ }
+
+ return pcm;
+}
+
+static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
+{
+ if (err > 0)
+ err = -err;
+ if (err == -EINTR) /* nothing to do, continue */
+ return 0;
+ if (err == -EPIPE) {
+ AUDIO_LOG_INFO("XRUN occurred");
+ err = pcm_prepare(pcm);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Could not recover from XRUN occurred, prepare failed : %d", err);
+ return err;
+ }
+ return 0;
+ }
+ if (err == -ESTRPIPE) {
+ /* tinyalsa does not support pcm resume, dont't care suspend case */
+ AUDIO_LOG_ERROR("Could not recover from suspend : %d", err);
+ return err;
+ }
+ return err;
+}
+#endif
+
+#ifndef __USE_TINYALSA__
+static int __make_alsa_device_name(const char *card, const char *device, char device_name[])
+{
+ AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(device_name, AUDIO_ERR_PARAMETER);
+
+ snprintf(device_name, DEVICE_NAME_MAX, "hw:%s,%s", card, device);
+ return 0;
+}
+#endif
+
+audio_return_e _pcm_open(const char *card, const char *device, uint32_t direction, void *sample_spec,
+ uint32_t period_size, uint32_t periods, void **pcm_handle)
+{
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((direction == AUDIO_DIRECTION_OUT) || (direction == AUDIO_DIRECTION_IN),
+ AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("card(%s) device(%s) direction(%u) period_size(%u) periods(%u)",
+ card, device, direction, period_size, periods);
+#ifdef __USE_TINYALSA__
+ audio_pcm_sample_spec_s *ss;
+
+ ss = (audio_pcm_sample_spec_s *)sample_spec;
+ ss->format = __convert_format((audio_sample_format_s)ss->format);
+
+ *pcm_handle = __tinyalsa_open_device(card, device, ss, (size_t)period_size, (size_t)periods, direction);
+ if (*pcm_handle == NULL) {
+ AUDIO_LOG_ERROR("Error opening PCM device");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((err = pcm_prepare((struct pcm *)*pcm_handle)) != 0) {
+ AUDIO_LOG_ERROR("Error prepare PCM device : %d", err);
+ }
+
+#else /* alsa-lib */
+ int mode;
+ audio_return_e ret;
+ char device_name[DEVICE_NAME_MAX];
+
+ __make_alsa_device_name(card, device, device_name);
+ mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
+
+ if ((err = snd_pcm_open((snd_pcm_t **)pcm_handle, device_name, (direction == AUDIO_DIRECTION_OUT) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, mode)) < 0) {
+ AUDIO_LOG_ERROR("Error opening PCM device %s : %s", device_name, snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((ret = _pcm_set_params(*pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", ret);
+ return ret;
+ }
+
+ AUDIO_LOG_INFO("PCM device %s", device_name);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_start(void *pcm_handle)
+{
+ int err;
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_start(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error starting PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_start(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error starting PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ AUDIO_LOG_INFO("PCM handle %p start", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_stop(void *pcm_handle)
+{
+ int err;
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_stop(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error stopping PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_drop(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error stopping PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ AUDIO_LOG_INFO("PCM handle %p stop", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_close(void *pcm_handle)
+{
+ int err;
+
+ AUDIO_LOG_INFO("Try to close PCM handle %p", pcm_handle);
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_close(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error closing PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_close(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_avail(void *pcm_handle, uint32_t *avail)
+{
+#ifdef __USE_TINYALSA__
+ struct timespec tspec;
+ unsigned int frames_avail = 0;
+ int err;
+
+ err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle %p : %d", pcm_handle, err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("avail = %d", frames_avail);
+#endif
+
+ *avail = (uint32_t)frames_avail;
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_avail;
+
+ if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not get avail at PCM handle %p : %ld", pcm_handle, frames_avail);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("avail = %d", frames_avail);
+#endif
+
+ *avail = (uint32_t)frames_avail;
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ err = pcm_write(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Failed to write pcm : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_write = %d", frames);
+#endif
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_written;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ frames_written = snd_pcm_writei(pcm_handle, buffer, (snd_pcm_uframes_t) frames);
+ if (frames_written < 0) {
+ AUDIO_LOG_ERROR("Failed to write pcm : %ld", frames_written);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_write = (%d / %d)", frames_written, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ err = pcm_read(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Failed to read pcm : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("audio_pcm_read = %d", frames);
+#endif
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_read;
+
+ frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
+ if (frames_read < 0) {
+ AUDIO_LOG_ERROR("Failed to read pcm : %ld", frames_read);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_read = (%d / %d)", frames_read, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_get_fd(void *pcm_handle, int *fd)
+{
+ /* we use an internal API of the (tiny)alsa library, so it causes warning message during compile */
+#ifdef __USE_TINYALSA__
+ *fd = _pcm_poll_descriptor((struct pcm *)pcm_handle);
+#else /* alsa-lib */
+ *fd = _snd_pcm_poll_descriptor((snd_pcm_t *)pcm_handle);
+#endif
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_recover(void *pcm_handle, int revents)
+{
+ int state, err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ if (revents & POLLERR)
+ AUDIO_LOG_DEBUG("Got POLLERR from ALSA");
+ if (revents & POLLNVAL)
+ AUDIO_LOG_DEBUG("Got POLLNVAL from ALSA");
+ if (revents & POLLHUP)
+ AUDIO_LOG_DEBUG("Got POLLHUP from ALSA");
+ if (revents & POLLPRI)
+ AUDIO_LOG_DEBUG("Got POLLPRI from ALSA");
+ if (revents & POLLIN)
+ AUDIO_LOG_DEBUG("Got POLLIN from ALSA");
+ if (revents & POLLOUT)
+ AUDIO_LOG_DEBUG("Got POLLOUT from ALSA");
+
+#ifdef __USE_TINYALSA__
+ state = pcm_state(pcm_handle);
+ AUDIO_LOG_DEBUG("PCM state is %d", state);
+
+ switch (state) {
+ case PCM_STATE_XRUN:
+ if ((err = __tinyalsa_pcm_recover(pcm_handle, -EPIPE)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ case PCM_STATE_SUSPENDED:
+ if ((err = __tinyalsa_pcm_recover(pcm_handle, -ESTRPIPE)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ default:
+ pcm_stop(pcm_handle);
+ if ((err = pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with pcm_prepare() : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ }
+#else /* alsa-lib */
+ state = snd_pcm_state(pcm_handle);
+ AUDIO_LOG_DEBUG("PCM state is %s", snd_pcm_state_name(state));
+
+ /* Try to recover from this error */
+
+ switch (state) {
+ case SND_PCM_STATE_XRUN:
+ if ((err = snd_pcm_recover(pcm_handle, -EPIPE, 1)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ case SND_PCM_STATE_SUSPENDED:
+ if ((err = snd_pcm_recover(pcm_handle, -ESTRPIPE, 1)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ default:
+ snd_pcm_drop(pcm_handle);
+ if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare() : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+ }
+#endif
+
+ AUDIO_LOG_DEBUG("_pcm_recover");
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
+{
+#ifdef __USE_TINYALSA__
+ audio_pcm_sample_spec_s *ss;
+ unsigned int _period_size, _buffer_size, _periods, _format, _rate, _channels;
+ unsigned int _start_threshold, _stop_threshold, _silence_threshold;
+ struct pcm_config *config;
+
+ ss = (audio_pcm_sample_spec_s *)*sample_spec;
+
+ /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
+ _pcm_config(pcm_handle, &config);
+
+ *period_size = config->period_size;
+ *periods = config->period_count;
+ _buffer_size = config->period_size * config->period_count;
+ ss->format = config->format;
+ ss->rate = config->rate;
+ ss->channels = config->channels;
+ _start_threshold = config->start_threshold;
+ _stop_threshold = config->stop_threshold;
+ _silence_threshold = config->silence_threshold;
+
+ AUDIO_LOG_DEBUG("_pcm_get_params (handle %p, format %d, rate %u, channels %u, period_size %u, periods %u, buffer_size %u)",
+ pcm_handle, config->format, config->rate, config->channels, config->period_size, config->period_count, _buffer_size);
+#else /* alsa-lib */
+ int err;
+ audio_pcm_sample_spec_s *ss;
+ int dir;
+ snd_pcm_uframes_t _period_size = 0 , _buffer_size = 0;
+ snd_pcm_format_t _format;
+ unsigned int _rate = 0, _channels = 0;
+ snd_pcm_uframes_t _start_threshold = 0, _stop_threshold = 0, _silence_threshold = 0, _avail_min = 0;
+ unsigned int _periods = 0;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = (audio_pcm_sample_spec_s *)*sample_spec;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_sw_params_alloca(&swparams);
+
+ if ((err = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_current() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0 ||
+ (err = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_format(hwparams, &_format)) < 0 ||
+ (err = snd_pcm_hw_params_get_rate(hwparams, &_rate, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_channels(hwparams, &_channels)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ *period_size = _period_size;
+ *periods = _periods;
+ ss->format = _format;
+ ss->rate = _rate;
+ ss->channels = _channels;
+
+ if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_get_start_threshold(swparams, &_start_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_stop_threshold(swparams, &_stop_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_silence_threshold(swparams, &_silence_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_avail_min(swparams, &_avail_min)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %d", err);
+ }
+
+ AUDIO_LOG_DEBUG("_pcm_get_params (handle %p, format %d, rate %u, channels %u, period_size %lu, periods %u, buffer_size %lu,",
+ pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size);
+ AUDIO_LOG_DEBUG(" start_threshold %lu, stop_threshold %lu, silence_threshold %lu, avail_min %lu)",
+ _start_threshold, _stop_threshold, _silence_threshold, _avail_min);
+
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+#ifdef __USE_TINYALSA__
+ /* Parameters are only acceptable in pcm_open() function */
+ AUDIO_LOG_DEBUG("_pcm_set_params");
+#else /* alsa-lib */
+ int err;
+ audio_pcm_sample_spec_s ss;
+ snd_pcm_uframes_t _buffer_size;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = *(audio_pcm_sample_spec_s *)sample_spec;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_sw_params_alloca(&swparams);
+
+ /* Set hw params */
+ if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate_resample() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ ss.format = __convert_format((audio_sample_format_s)ss.format);
+ if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, ss.format)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_format() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", ss.channels, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_period_size(pcm_handle, hwparams, period_size, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size(%u) failed : %d", period_size, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods(%u) failed : %d", periods, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ _buffer_size = period_size * periods;
+ if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, _buffer_size)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size(%lu) failed : %d", _buffer_size, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ /* Set sw params */
+ if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("Unable to determine current swparams : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm_handle, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
+ AUDIO_LOG_ERROR("Unable to enable time stamping : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xFFFFFFFF)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set stop threshold : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, _buffer_size)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set start threshold : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, period_size)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set sw params : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ /* Prepare device */
+ if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_prepare() failed : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ AUDIO_LOG_DEBUG("_pcm_set_params (handle %p, format %d, rate %u, channels %u, period_size %u, periods %u, buffer_size %lu)",
+ pcm_handle, ss.format, ss.rate, ss.channels, period_size, periods, _buffer_size);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+/* Generic snd pcm interface APIs */
+audio_return_e _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_s *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size)
+{
+ audio_return_e ret = AUDIO_RET_OK;
+ snd_pcm_hw_params_t *hwparams;
+ int err = 0;
+ int dir;
+ unsigned int val = 0;
+ snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
+ snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
+ uint8_t _use_mmap = use_mmap && *use_mmap;
+ uint32_t channels = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ /* Skip parameter setting to null device. */
+ if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
+ return AUDIO_ERR_IOCTL;
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ /* Fill it in with default values. */
+ if (snd_pcm_hw_params_any(pcm, hwparams) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Set the desired hardware parameters. */
+
+ if (_use_mmap) {
+
+ if (snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
+
+ /* mmap() didn't work, fall back to interleaved */
+
+ if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ _use_mmap = 0;
+ }
+
+ } else if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+ AUDIO_LOG_DEBUG("setting rate - %d", sample_spec->rate);
+ err = snd_pcm_hw_params_set_rate(pcm, hwparams, sample_spec->rate, 0);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
+ }
+
+ err = snd_pcm_hw_params(pcm, hwparams);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Dump current param */
+
+ if ((ret = snd_pcm_hw_params_current(pcm, hwparams)) < 0) {
+ AUDIO_LOG_INFO("snd_pcm_hw_params_current() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
+ (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
+ AUDIO_LOG_INFO("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
+ AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
+
+ snd_pcm_hw_params_get_format(hwparams, &sample_spec->format);
+ AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
+ snd_pcm_format_name((snd_pcm_format_t)sample_spec->format),
+ snd_pcm_format_description((snd_pcm_format_t)sample_spec->format));
+
+ snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
+ AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
+ snd_pcm_subformat_name((snd_pcm_subformat_t)val),
+ snd_pcm_subformat_description((snd_pcm_subformat_t)val));
+
+ snd_pcm_hw_params_get_channels(hwparams, &channels);
+ sample_spec->channels = (uint8_t)channels;
+ AUDIO_LOG_DEBUG("channels = %d\n", sample_spec->channels);
+
+ if (buffer_size)
+ *buffer_size = _buffer_size;
+
+ if (period_size)
+ *period_size = _period_size;
+
+ if (use_mmap)
+ *use_mmap = _use_mmap;
+
+ return AUDIO_RET_OK;
+
+error:
+ return AUDIO_ERR_RESOURCE;
+}
+
+audio_return_e _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event)
+{
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_uframes_t boundary;
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ snd_pcm_sw_params_alloca(&swparams);
+
+ if ((err = snd_pcm_sw_params_current(pcm, swparams)) < 0) {
+ AUDIO_LOG_WARN("Unable to determine current swparams: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
+ AUDIO_LOG_WARN("Unable to disable period event: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
+ AUDIO_LOG_WARN("Unable to enable time stamping: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
+ AUDIO_LOG_WARN("Unable to get boundary: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
+ AUDIO_LOG_WARN("Unable to set stop threshold: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) avail_min)) < 0) {
+ AUDIO_LOG_WARN("Unable to set start threshold: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
+ AUDIO_LOG_WARN("snd_pcm_sw_params_set_avail_min() failed: %s", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
+ AUDIO_LOG_WARN("Unable to set sw params: %s\n", snd_strerror(err));
+ goto error;
+ }
+ return AUDIO_RET_OK;
+error:
+ return err;
+}
diff --git a/tizen-audio-impl.h b/tizen-audio-impl.h
new file mode 100644
index 0000000..6f916ea
--- /dev/null
+++ b/tizen-audio-impl.h
@@ -0,0 +1,47 @@
+#ifndef footizenaudioimplfoo
+#define footizenaudioimplfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+/* PCM */
+audio_return_e _pcm_open(const char *card, const char *device, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods, void **pcm_handle);
+audio_return_e _pcm_start(void *pcm_handle);
+audio_return_e _pcm_stop(void *pcm_handle);
+audio_return_e _pcm_close(void *pcm_handle);
+audio_return_e _pcm_avail(void *pcm_handle, uint32_t *avail);
+audio_return_e _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames);
+audio_return_e _pcm_read(void *pcm_handle, void *buffer, uint32_t frames);
+audio_return_e _pcm_get_fd(void *pcm_handle, int *fd);
+audio_return_e _pcm_recover(void *pcm_handle, int revents);
+audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_e _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event);
+audio_return_e _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_s *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size);
+
+/* Control */
+audio_return_e _mixer_control_init(audio_hal_s *ah);
+audio_return_e _mixer_control_deinit(audio_hal_s *ah);
+audio_return_e _mixer_control_set_param(audio_hal_s *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
+audio_return_e _mixer_control_set_value(audio_hal_s *ah, const char* card, const char *ctl_name, int val);
+audio_return_e _mixer_control_set_value_string(audio_hal_s *ah, const char* ctl_name, const char* value);
+audio_return_e _mixer_control_get_value(audio_hal_s *ah, const char *card, const char *ctl_name, int *val);
+audio_return_e _mixer_control_get_element(audio_hal_s *ah, const char *ctl_name, snd_hctl_elem_t **elem);
+
+#endif
diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h
new file mode 100644
index 0000000..d8e6b5f
--- /dev/null
+++ b/tizen-audio-internal.h
@@ -0,0 +1,252 @@
+#ifndef footizenaudiointernalfoo
+#define footizenaudiointernalfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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 <dlog.h>
+#include <time.h>
+#include <sys/types.h>
+#include <asoundlib.h>
+#ifdef __USE_TINYALSA__
+#include <tinyalsa/asoundlib.h>
+#endif
+#include <pthread.h>
+#include <use-case.h>
+#include "tizen-audio.h"
+
+/* Debug */
+
+//#define AUDIO_DEBUG
+#define PROPERTY_VALUE_MAX 92
+#define BUF_SIZE 1024
+#define AUDIO_DUMP_STR_LEN 256
+#define AUDIO_DEVICE_INFO_LIST_MAX 16
+#ifdef USE_DLOG
+#ifdef DLOG_TAG
+#undef DLOG_TAG
+#endif
+#define DLOG_TAG "AUDIO_HAL"
+#define AUDIO_LOG_ERROR(...) SLOG(LOG_ERROR, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_WARN(...) SLOG(LOG_WARN, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_INFO(...) SLOG(LOG_INFO, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_DEBUG(...) SLOG(LOG_DEBUG, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_VERBOSE(...) SLOG(LOG_DEBUG, DLOG_TAG, __VA_ARGS__)
+#else
+#define AUDIO_LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
+#define AUDIO_LOG_WARN(...) fprintf(stderr, __VA_ARGS__)
+#define AUDIO_LOG_INFO(...) fprintf(stdout, __VA_ARGS__)
+#define AUDIO_LOG_DEBUG(...) fprintf(stdout, __VA_ARGS__)
+#define AUDIO_LOG_VERBOSE(...) fprintf(stdout, __VA_ARGS__)
+#endif
+
+#define AUDIO_RETURN_IF_FAIL(expr) do { \
+ if (!(expr)) { \
+ AUDIO_LOG_ERROR("%s failed", #expr); \
+ return; \
+ } \
+} while (0)
+#define AUDIO_RETURN_VAL_IF_FAIL(expr, val) do { \
+ if (!(expr)) { \
+ AUDIO_LOG_ERROR("%s failed", #expr); \
+ return val; \
+ } \
+} while (0)
+#define AUDIO_RETURN_NULL_IF_FAIL(expr) do { \
+ if (!(expr)) { \
+ AUDIO_LOG_ERROR("%s failed", #expr); \
+ return NULL; \
+ } \
+} while (0)
+
+/* Devices : Normal */
+#define AUDIO_DEVICE_OUT 0x00000000
+#define AUDIO_DEVICE_IN 0x80000000
+enum audio_device_type {
+ AUDIO_DEVICE_NONE = 0,
+
+ /* output devices */
+ AUDIO_DEVICE_OUT_SPEAKER = AUDIO_DEVICE_OUT | 0x00000001,
+ AUDIO_DEVICE_OUT_RECEIVER = AUDIO_DEVICE_OUT | 0x00000002,
+ AUDIO_DEVICE_OUT_JACK = AUDIO_DEVICE_OUT | 0x00000004,
+ AUDIO_DEVICE_OUT_BT_SCO = AUDIO_DEVICE_OUT | 0x00000008,
+ AUDIO_DEVICE_OUT_AUX = AUDIO_DEVICE_OUT | 0x00000010,
+ AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT | 0x00000020,
+ AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_RECEIVER |
+ AUDIO_DEVICE_OUT_JACK |
+ AUDIO_DEVICE_OUT_BT_SCO |
+ AUDIO_DEVICE_OUT_AUX |
+ AUDIO_DEVICE_OUT_HDMI),
+ /* input devices */
+ AUDIO_DEVICE_IN_MAIN_MIC = AUDIO_DEVICE_IN | 0x00000001,
+ AUDIO_DEVICE_IN_SUB_MIC = AUDIO_DEVICE_IN | 0x00000002,
+ AUDIO_DEVICE_IN_JACK = AUDIO_DEVICE_IN | 0x00000004,
+ AUDIO_DEVICE_IN_BT_SCO = AUDIO_DEVICE_IN | 0x00000008,
+ AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_MAIN_MIC |
+ AUDIO_DEVICE_IN_SUB_MIC |
+ AUDIO_DEVICE_IN_JACK |
+ AUDIO_DEVICE_IN_BT_SCO),
+};
+
+#define streq !strcmp
+#define strneq strcmp
+
+#define MAX_DEVICES 5
+#define MAX_NAME_LEN 32
+
+/* type definitions */
+typedef signed char int8_t;
+
+typedef struct device_type {
+ uint32_t type;
+ const char *name;
+} device_type_s;
+
+/* PCM */
+typedef struct {
+ snd_pcm_format_t format;
+ uint32_t rate;
+ uint8_t channels;
+} audio_pcm_sample_spec_s;
+
+typedef struct audio_hal_device {
+ uint32_t active_in;
+ uint32_t active_out;
+ snd_pcm_t *pcm_in;
+ snd_pcm_t *pcm_out;
+ pthread_mutex_t pcm_lock;
+ uint32_t pcm_count;
+} audio_hal_device_s;
+
+/* Volume */
+#define AUDIO_VOLUME_LEVEL_MAX 16
+
+typedef enum audio_volume {
+ AUDIO_VOLUME_TYPE_SYSTEM, /**< System volume type */
+ AUDIO_VOLUME_TYPE_NOTIFICATION, /**< Notification volume type */
+ AUDIO_VOLUME_TYPE_ALARM, /**< Alarm volume type */
+ AUDIO_VOLUME_TYPE_RINGTONE, /**< Ringtone volume type */
+ AUDIO_VOLUME_TYPE_MEDIA, /**< Media volume type */
+ AUDIO_VOLUME_TYPE_CALL, /**< Call volume type */
+ AUDIO_VOLUME_TYPE_VOIP, /**< VOIP volume type */
+ AUDIO_VOLUME_TYPE_VOICE, /**< Voice volume type */
+ AUDIO_VOLUME_TYPE_MAX, /**< Volume type count */
+} audio_volume_e;
+
+typedef enum audio_gain {
+ AUDIO_GAIN_TYPE_DEFAULT,
+ AUDIO_GAIN_TYPE_DIALER,
+ AUDIO_GAIN_TYPE_TOUCH,
+ AUDIO_GAIN_TYPE_AF,
+ AUDIO_GAIN_TYPE_SHUTTER1,
+ AUDIO_GAIN_TYPE_SHUTTER2,
+ AUDIO_GAIN_TYPE_CAMCODING,
+ AUDIO_GAIN_TYPE_MIDI,
+ AUDIO_GAIN_TYPE_BOOTING,
+ AUDIO_GAIN_TYPE_VIDEO,
+ AUDIO_GAIN_TYPE_TTS,
+ AUDIO_GAIN_TYPE_MAX,
+} audio_gain_e;
+
+typedef struct audio_volume_value_table {
+ double volume[AUDIO_VOLUME_TYPE_MAX][AUDIO_VOLUME_LEVEL_MAX];
+ double gain[AUDIO_GAIN_TYPE_MAX];
+} audio_volume_value_table_s;
+
+enum {
+ AUDIO_VOLUME_DEVICE_DEFAULT,
+ AUDIO_VOLUME_DEVICE_MAX,
+};
+
+typedef struct audio_hal_volume {
+ uint32_t volume_level_max[AUDIO_VOLUME_LEVEL_MAX];
+ uint32_t volume_level[AUDIO_VOLUME_TYPE_MAX];
+ audio_volume_value_table_s *volume_value_table;
+} audio_hal_volume_s;
+
+/* Mixer */
+typedef struct audio_hal_mixer {
+ snd_mixer_t *mixer;
+ pthread_mutex_t mutex;
+ struct {
+ snd_ctl_elem_value_t *value;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ } control;
+} audio_hal_mixer_s;
+
+/* Audio format */
+typedef enum audio_sample_format {
+ AUDIO_SAMPLE_U8,
+ AUDIO_SAMPLE_ALAW,
+ AUDIO_SAMPLE_ULAW,
+ AUDIO_SAMPLE_S16LE,
+ AUDIO_SAMPLE_S16BE,
+ AUDIO_SAMPLE_FLOAT32LE,
+ AUDIO_SAMPLE_FLOAT32BE,
+ AUDIO_SAMPLE_S32LE,
+ AUDIO_SAMPLE_S32BE,
+ AUDIO_SAMPLE_S24LE,
+ AUDIO_SAMPLE_S24BE,
+ AUDIO_SAMPLE_S24_32LE,
+ AUDIO_SAMPLE_S24_32BE,
+ AUDIO_SAMPLE_MAX,
+ AUDIO_SAMPLE_INVALID = -1
+} audio_sample_format_s;
+
+typedef struct audio_hal_comm {
+ message_cb msg_cb;
+ void *user_data;
+} audio_hal_comm_s;
+
+/* Overall */
+typedef struct audio_hal {
+ audio_hal_device_s device;
+ audio_hal_volume_s volume;
+ audio_hal_mixer_s mixer;
+ audio_hal_comm_s comm;
+} audio_hal_s;
+
+audio_return_e _audio_ctrl_init(audio_hal_s *ah);
+audio_return_e _audio_ctrl_deinit(audio_hal_s *ah);
+audio_return_e _audio_volume_init(audio_hal_s *ah);
+audio_return_e _audio_volume_deinit(audio_hal_s *ah);
+audio_return_e _audio_routing_init(audio_hal_s *ah);
+audio_return_e _audio_routing_deinit(audio_hal_s *ah);
+audio_return_e _audio_stream_init(audio_hal_s *ah);
+audio_return_e _audio_stream_deinit(audio_hal_s *ah);
+audio_return_e _audio_pcm_init(audio_hal_s *ah);
+audio_return_e _audio_pcm_deinit(audio_hal_s *ah);
+audio_return_e _audio_comm_init(audio_hal_s *ah);
+audio_return_e _audio_comm_deinit(audio_hal_s *ah);
+audio_return_e _audio_comm_send_message(audio_hal_s *ah, const char *name, int value);
+
+typedef struct _dump_data {
+ char *strbuf;
+ int left;
+ char *p;
+} dump_data_t;
+
+dump_data_t* _audio_dump_new(int length);
+void _audio_dump_add_str(dump_data_t *dump, const char *fmt, ...);
+char* _audio_dump_get_str(dump_data_t *dump);
+void _audio_dump_free(dump_data_t *dump);
+
+#endif
diff --git a/tizen-audio-pcm.c b/tizen-audio-pcm.c
new file mode 100644
index 0000000..4a4cf53
--- /dev/null
+++ b/tizen-audio-pcm.c
@@ -0,0 +1,204 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+audio_return_e _audio_pcm_init(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.pcm_in = NULL;
+ ah->device.pcm_out = NULL;
+ pthread_mutex_init(&ah->device.pcm_lock, NULL);
+ ah->device.pcm_count = 0;
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _audio_pcm_deinit(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_destroy(&ah->device.pcm_lock);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_pcm_open(void *audio_handle, const char *card, const char *device, uint32_t direction, void *sample_spec,
+ uint32_t period_size, uint32_t periods, void **pcm_handle)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _pcm_open(card, device, direction, sample_spec, period_size, periods, pcm_handle)))
+ return audio_ret;
+
+ ah = (audio_hal_s*)audio_handle;
+ ah->device.pcm_count++;
+ AUDIO_LOG_INFO("Opening PCM handle %p", *pcm_handle);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_pcm_start(void *audio_handle, void *pcm_handle)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_start(pcm_handle);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_stop(void *audio_handle, void *pcm_handle)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_stop(pcm_handle);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_close(void *audio_handle, void *pcm_handle)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _pcm_close(pcm_handle)))
+ return audio_ret;
+
+ pcm_handle = NULL;
+ ah = (audio_hal_s*)audio_handle;
+ ah->device.pcm_count--;
+
+ AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_avail(pcm_handle, avail);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_write(pcm_handle, buffer, frames);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_read(pcm_handle, buffer, frames);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_get_fd(pcm_handle, fd);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_recover(pcm_handle, revents);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_get_params(pcm_handle, direction, sample_spec, period_size, periods);
+
+ return audio_ret;
+}
+
+audio_return_e audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_set_params(pcm_handle, direction, sample_spec, period_size, periods);
+
+ return audio_ret;
+}
diff --git a/tizen-audio-routing.c b/tizen-audio-routing.c
new file mode 100644
index 0000000..d0639a2
--- /dev/null
+++ b/tizen-audio-routing.c
@@ -0,0 +1,294 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+/* #define DEBUG_TIMING */
+
+static device_type_s outDeviceTypes[] = {
+ { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
+ { AUDIO_DEVICE_OUT_JACK, "Headphones" },
+ { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
+ { AUDIO_DEVICE_OUT_AUX, "Line" },
+ { AUDIO_DEVICE_OUT_HDMI, "HDMI" },
+ { 0, 0 },
+};
+
+static device_type_s inDeviceTypes[] = {
+ { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
+ { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
+ { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
+ { 0, 0 },
+};
+
+static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
+{
+ uint32_t device = 0;
+
+ if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_RECEIVER;
+ } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_JACK;
+ } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_BT_SCO;
+ } else if (!strncmp(device_str, "aux", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_AUX;
+ } else if (!strncmp(device_str, "hdmi", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_HDMI;
+ } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
+ device = AUDIO_DEVICE_IN_MAIN_MIC;
+ } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_JACK;
+ } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_BT_SCO;
+ } else {
+ device = AUDIO_DEVICE_NONE;
+ }
+ AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
+ return device;
+}
+
+static audio_return_e __set_devices(audio_hal_s *ah, device_info_s *devices, uint32_t num_of_devices)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ uint32_t new_device = 0;
+ const char *active_devices[MAX_DEVICES] = {NULL,};
+ int i = 0, j = 0, dev_idx = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
+
+ if (num_of_devices > MAX_DEVICES) {
+ num_of_devices = MAX_DEVICES;
+ AUDIO_LOG_ERROR("error: num_of_devices");
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if (devices[0].direction == AUDIO_DIRECTION_OUT) {
+ ah->device.active_out &= 0x0;
+ if (ah->device.active_in) {
+ /* check the active in devices */
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ }
+ }
+ } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
+ ah->device.active_in &= 0x0;
+ if (ah->device.active_out) {
+ /* check the active out devices */
+ for (j = 0; j < outDeviceTypes[j].type; j++) {
+ if (ah->device.active_out & outDeviceTypes[j].type)
+ active_devices[dev_idx++] = outDeviceTypes[j].name;
+ }
+ }
+ }
+
+ for (i = 0; i < num_of_devices; i++) {
+ new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
+ if (new_device & AUDIO_DEVICE_IN) {
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (new_device == inDeviceTypes[j].type) {
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ ah->device.active_in |= new_device;
+ }
+ }
+ } else {
+ for (j = 0; j < outDeviceTypes[j].type; j++) {
+ if (new_device == outDeviceTypes[j].type) {
+ active_devices[dev_idx++] = outDeviceTypes[j].name;
+ ah->device.active_out |= new_device;
+ }
+ }
+ }
+ }
+
+ if (active_devices[0] == NULL) {
+ AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ /* TODO : Set device here */
+
+ return audio_ret;
+}
+
+static audio_return_e __update_route_ap_playback_capture(audio_hal_s *ah, audio_route_info_s *route_info)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ device_info_s *devices = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
+
+ devices = route_info->device_infos;
+
+ AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
+
+ audio_ret = __set_devices(ah, devices, route_info->num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ return audio_ret;
+}
+
+static audio_return_e __update_route_voip(audio_hal_s *ah, device_info_s *devices, int32_t num_of_devices)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voip++");
+
+ audio_ret = __set_devices(ah, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ return audio_ret;
+}
+
+static audio_return_e __update_route_reset(audio_hal_s *ah, uint32_t direction)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ const char *active_devices[MAX_DEVICES] = {NULL,};
+ int i = 0, dev_idx = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
+
+ if (direction == AUDIO_DIRECTION_OUT) {
+ ah->device.active_out &= 0x0;
+ if (ah->device.active_in) {
+ /* check the active in devices */
+ for (i = 0; i < inDeviceTypes[i].type; i++) {
+ if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
+ active_devices[dev_idx++] = inDeviceTypes[i].name;
+ AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
+ }
+ }
+ }
+ } else {
+ ah->device.active_in &= 0x0;
+ if (ah->device.active_out) {
+ /* check the active out devices */
+ for (i = 0; i < outDeviceTypes[i].type; i++) {
+ if (ah->device.active_out & outDeviceTypes[i].type) {
+ active_devices[dev_idx++] = outDeviceTypes[i].name;
+ AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
+ }
+ }
+ }
+ }
+
+ if (active_devices[0] == NULL) {
+ AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
+ return AUDIO_RET_OK;
+ }
+
+ return audio_ret;
+}
+
+audio_return_e _audio_routing_init(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.active_in = 0x0;
+ ah->device.active_out = 0x0;
+
+ /* TODO : Device init here */
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _audio_routing_deinit(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ /* TODO : Device deinit here */
+
+ return AUDIO_RET_OK;
+}
+
+#define LOOPBACK_ARG_LATENCY_MSEC 30
+#define LOOPBACK_ARG_ADJUST_TIME_SEC 3
+audio_return_e audio_update_route(void *audio_handle, audio_route_info_s *info)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+ device_info_s *devices = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info->role, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s", info->role);
+
+ devices = info->device_infos;
+
+ if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
+
+ } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_reset(ah, devices->direction)))
+ AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
+
+ } else {
+ /* send latency and adjust time for loopback */
+ if (!strncmp("loopback", info->role, MAX_NAME_LEN)) {
+ _audio_comm_send_message(ah, "loopback::latency", LOOPBACK_ARG_LATENCY_MSEC);
+ _audio_comm_send_message(ah, "loopback::adjust_time", LOOPBACK_ARG_ADJUST_TIME_SEC);
+ }
+ /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
+ if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
+ AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
+ }
+ return audio_ret;
+}
+
+audio_return_e audio_update_route_option(void *audio_handle, audio_route_option_s *option)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
+
+ return audio_ret;
+}
diff --git a/tizen-audio-stream.c b/tizen-audio-stream.c
new file mode 100644
index 0000000..2f5594b
--- /dev/null
+++ b/tizen-audio-stream.c
@@ -0,0 +1,54 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+audio_return_e _audio_stream_init(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _audio_stream_deinit(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_s *info, uint32_t is_connected)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info->role, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((info->direction <= AUDIO_DIRECTION_OUT), AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
+
+ return audio_ret;
+}
+
diff --git a/tizen-audio-util.c b/tizen-audio-util.c
new file mode 100644
index 0000000..c81dfe3
--- /dev/null
+++ b/tizen-audio-util.c
@@ -0,0 +1,80 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tizen-audio-internal.h"
+
+/* ------ dump helper -------- */
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+dump_data_t* _audio_dump_new(int length)
+{
+ dump_data_t* dump = NULL;
+
+ if ((dump = malloc(sizeof(dump_data_t)))) {
+ memset(dump, 0, sizeof(dump_data_t));
+ if ((dump->strbuf = malloc(length))) {
+ dump->p = &dump->strbuf[0];
+ dump->left = length;
+ } else {
+ free(dump);
+ dump = NULL;
+ }
+ }
+
+ return dump;
+}
+
+void _audio_dump_add_str(dump_data_t *dump, const char *fmt, ...)
+{
+ int len;
+ va_list ap;
+
+ if (!dump)
+ return;
+
+ va_start(ap, fmt);
+ len = vsnprintf(dump->p, dump->left, fmt, ap);
+ va_end(ap);
+
+ dump->p += MAX(0, len);
+ dump->left -= MAX(0, len);
+}
+
+char* _audio_dump_get_str(dump_data_t *dump)
+{
+ return (dump) ? dump->strbuf : NULL;
+}
+
+void _audio_dump_free(dump_data_t *dump)
+{
+ if (dump) {
+ if (dump->strbuf)
+ free(dump->strbuf);
+ free(dump);
+ }
+}
+/* ------ dump helper -------- */
diff --git a/tizen-audio-volume.c b/tizen-audio-volume.c
new file mode 100644
index 0000000..e9b9177
--- /dev/null
+++ b/tizen-audio-volume.c
@@ -0,0 +1,452 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <vconf.h>
+#include <iniparser.h>
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+#define VOLUME_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_audio_volume.ini" /* SYSCONFDIR is defined at .spec */
+#define VOLUME_INI_TEMP_PATH "/opt/system/mmfw_audio_volume.ini"
+#define VOLUME_VALUE_MAX (1.0f)
+#define GAIN_VALUE_MAX (1.0f)
+
+static uint32_t g_master_volume_level = 100;
+
+static const char *g_volume_vconf[AUDIO_VOLUME_TYPE_MAX] = {
+ "file/private/sound/volume/system", /* AUDIO_VOLUME_TYPE_SYSTEM */
+ "file/private/sound/volume/notification", /* AUDIO_VOLUME_TYPE_NOTIFICATION */
+ "file/private/sound/volume/alarm", /* AUDIO_VOLUME_TYPE_ALARM */
+ "file/private/sound/volume/ringtone", /* AUDIO_VOLUME_TYPE_RINGTONE */
+ "file/private/sound/volume/media", /* AUDIO_VOLUME_TYPE_MEDIA */
+ "file/private/sound/volume/call", /* AUDIO_VOLUME_TYPE_CALL */
+ "file/private/sound/volume/voip", /* AUDIO_VOLUME_TYPE_VOIP */
+ "file/private/sound/volume/voice", /* AUDIO_VOLUME_TYPE_VOICE */
+};
+
+static const char *__get_volume_type_string_by_idx(uint32_t vol_type_idx)
+{
+ switch (vol_type_idx) {
+ case AUDIO_VOLUME_TYPE_SYSTEM: return "system";
+ case AUDIO_VOLUME_TYPE_NOTIFICATION: return "notification";
+ case AUDIO_VOLUME_TYPE_ALARM: return "alarm";
+ case AUDIO_VOLUME_TYPE_RINGTONE: return "ringtone";
+ case AUDIO_VOLUME_TYPE_MEDIA: return "media";
+ case AUDIO_VOLUME_TYPE_CALL: return "call";
+ case AUDIO_VOLUME_TYPE_VOIP: return "voip";
+ case AUDIO_VOLUME_TYPE_VOICE: return "voice";
+ default: return "invalid";
+ }
+}
+
+static uint32_t __get_volume_idx_by_string_type(const char *vol_type)
+{
+ if (!strncmp(vol_type, "system", strlen(vol_type)) || !strncmp(vol_type, "0", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_SYSTEM;
+ else if (!strncmp(vol_type, "notification", strlen(vol_type)) || !strncmp(vol_type, "1", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_NOTIFICATION;
+ else if (!strncmp(vol_type, "alarm", strlen(vol_type)) || !strncmp(vol_type, "2", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_ALARM;
+ else if (!strncmp(vol_type, "ringtone", strlen(vol_type)) || !strncmp(vol_type, "3", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_RINGTONE;
+ else if (!strncmp(vol_type, "media", strlen(vol_type)) || !strncmp(vol_type, "4", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_MEDIA;
+ else if (!strncmp(vol_type, "call", strlen(vol_type)) || !strncmp(vol_type, "5", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_CALL;
+ else if (!strncmp(vol_type, "voip", strlen(vol_type)) || !strncmp(vol_type, "6", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_VOIP;
+ else if (!strncmp(vol_type, "voice", strlen(vol_type)) || !strncmp(vol_type, "7", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_VOICE;
+ else
+ return AUDIO_VOLUME_TYPE_MEDIA;
+}
+
+static const char *__get_gain_type_string_by_idx(uint32_t gain_type_idx)
+{
+ switch (gain_type_idx) {
+ case AUDIO_GAIN_TYPE_DEFAULT: return "default";
+ case AUDIO_GAIN_TYPE_DIALER: return "dialer";
+ case AUDIO_GAIN_TYPE_TOUCH: return "touch";
+ case AUDIO_GAIN_TYPE_AF: return "af";
+ case AUDIO_GAIN_TYPE_SHUTTER1: return "shutter1";
+ case AUDIO_GAIN_TYPE_SHUTTER2: return "shutter2";
+ case AUDIO_GAIN_TYPE_CAMCODING: return "camcording";
+ case AUDIO_GAIN_TYPE_MIDI: return "midi";
+ case AUDIO_GAIN_TYPE_BOOTING: return "booting";
+ case AUDIO_GAIN_TYPE_VIDEO: return "video";
+ case AUDIO_GAIN_TYPE_TTS: return "tts";
+ default: return "invalid";
+ }
+}
+
+static void __dump_tb(audio_hal_s *ah)
+{
+ audio_volume_value_table_s *volume_value_table = ah->volume.volume_value_table;
+ uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
+ const char *gain_type_str[] = {
+ "def", /* AUDIO_GAIN_TYPE_DEFAULT */
+ "dial", /* AUDIO_GAIN_TYPE_DIALER */
+ "touch", /* AUDIO_GAIN_TYPE_TOUCH */
+ "af", /* AUDIO_GAIN_TYPE_AF */
+ "shut1", /* AUDIO_GAIN_TYPE_SHUTTER1 */
+ "shut2", /* AUDIO_GAIN_TYPE_SHUTTER2 */
+ "cam", /* AUDIO_GAIN_TYPE_CAMCODING */
+ "midi", /* AUDIO_GAIN_TYPE_MIDI */
+ "boot", /* AUDIO_GAIN_TYPE_BOOTING */
+ "video", /* AUDIO_GAIN_TYPE_VIDEO */
+ "tts", /* AUDIO_GAIN_TYPE_TTS */
+ };
+ char dump_str[AUDIO_DUMP_STR_LEN], *dump_str_ptr;
+
+ /* Dump volume table */
+ AUDIO_LOG_INFO("<<<<< volume table >>>>>");
+
+ const char *table_str = "volumes";
+
+ AUDIO_LOG_INFO("<< %s >>", table_str);
+
+ for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_MAX; vol_type_idx++) {
+ const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
+
+ dump_str_ptr = &dump_str[0];
+ memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
+ snprintf(dump_str_ptr, 8, "%6s:", vol_type_str);
+ dump_str_ptr += strlen(dump_str_ptr);
+
+ for (vol_level_idx = 0; vol_level_idx < ah->volume.volume_level_max[vol_type_idx]; vol_level_idx++) {
+ snprintf(dump_str_ptr, 6, "%01.2f ", volume_value_table->volume[vol_type_idx][vol_level_idx]);
+ dump_str_ptr += strlen(dump_str_ptr);
+ }
+ AUDIO_LOG_INFO("%s", dump_str);
+ }
+
+ volume_value_table = ah->volume.volume_value_table;
+
+ /* Dump gain table */
+ AUDIO_LOG_INFO("<<<<< gain table >>>>>");
+
+ dump_str_ptr = &dump_str[0];
+ memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
+
+ snprintf(dump_str_ptr, 11, "%10s", " ");
+ dump_str_ptr += strlen(dump_str_ptr);
+
+ for (gain_type_idx = 0; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
+ snprintf(dump_str_ptr, 7, "%5s ", gain_type_str[gain_type_idx]);
+ dump_str_ptr += strlen(dump_str_ptr);
+ }
+ AUDIO_LOG_INFO("%s", dump_str);
+
+ dump_str_ptr = &dump_str[0];
+ memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
+
+ snprintf(dump_str_ptr, 11, "%9s:", table_str);
+ dump_str_ptr += strlen(dump_str_ptr);
+
+ for (gain_type_idx = 0; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
+ snprintf(dump_str_ptr, 7, "%01.3f ", volume_value_table->gain[gain_type_idx]);
+ dump_str_ptr += strlen(dump_str_ptr);
+ }
+ AUDIO_LOG_INFO("%s", dump_str);
+
+}
+
+static audio_return_e __load_volume_value_table_from_ini(audio_hal_s *ah)
+{
+ dictionary * dict = NULL;
+ uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
+ audio_volume_value_table_s *volume_value_table = ah->volume.volume_value_table;
+ int size = 0;
+ const char delimiter[] = ", ";
+ const char *table_str = "volumes";
+ const char *tmp_str = NULL;
+ const char *gain_str = NULL;
+ char *list_str = NULL, *ptr = NULL;
+ char *key, *token;
+
+ if (access(VOLUME_INI_TEMP_PATH, F_OK) == 0)
+ dict = iniparser_load(VOLUME_INI_TEMP_PATH);
+ if (!dict) {
+ AUDIO_LOG_DEBUG("Use default volume&gain ini file");
+ dict = iniparser_load(VOLUME_INI_DEFAULT_PATH);
+ if (!dict) {
+ AUDIO_LOG_WARN("Loading volume&gain table from ini file failed");
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+
+ /* Load volume table */
+ for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_MAX; vol_type_idx++) {
+ const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
+
+ ah->volume.volume_level_max[vol_type_idx] = 0;
+ size = strlen(table_str) + strlen(vol_type_str) + 2;
+ key = malloc(size);
+ if (key) {
+ snprintf(key, size, "%s:%s", table_str, vol_type_str);
+ if ((tmp_str = iniparser_getstring(dict, key, NULL)))
+ list_str = strdup(tmp_str);
+
+ if (list_str) {
+ token = strtok_r(list_str, delimiter, &ptr);
+ while (token) {
+ /* convert dB volume to linear volume */
+ double vol_value = 0.0f;
+ if (strncmp(token, "0", strlen(token)))
+ vol_value = pow(10.0, (atof(token) - 100) / 20.0);
+ volume_value_table->volume[vol_type_idx][ah->volume.volume_level_max[vol_type_idx]++] = vol_value;
+ token = strtok_r(NULL, delimiter, &ptr);
+ }
+ free(list_str);
+ list_str = NULL;
+ } else {
+ ah->volume.volume_level_max[vol_type_idx] = 1;
+ for (vol_level_idx = 0; vol_level_idx < AUDIO_VOLUME_LEVEL_MAX; vol_level_idx++) {
+ volume_value_table->volume[vol_type_idx][vol_level_idx] = VOLUME_VALUE_MAX;
+ }
+ }
+ free(key);
+ }
+ }
+
+ /* Load gain table */
+ volume_value_table->gain[AUDIO_GAIN_TYPE_DEFAULT] = GAIN_VALUE_MAX;
+ for (gain_type_idx = AUDIO_GAIN_TYPE_DEFAULT + 1; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++) {
+ const char *gain_type_str = __get_gain_type_string_by_idx(gain_type_idx);
+
+ size = strlen(table_str) + strlen("gain") + strlen(gain_type_str) + 3;
+ key = malloc(size);
+ if (key) {
+ snprintf(key, size, "%s:gain_%s", table_str, gain_type_str);
+ gain_str = iniparser_getstring(dict, key, NULL);
+ if (gain_str) {
+ volume_value_table->gain[gain_type_idx] = atof(gain_str);
+ } else {
+ volume_value_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
+ }
+ free(key);
+ } else {
+ volume_value_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
+ }
+ }
+
+ iniparser_freedict(dict);
+
+ __dump_tb(ah);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e _audio_volume_init(audio_hal_s *ah)
+{
+ int i;
+ int val = 0;
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ int init_value[AUDIO_VOLUME_TYPE_MAX] = { 9, 11, 7, 11, 7, 4, 4, 7 };
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
+ ah->volume.volume_level[i] = init_value[i];
+ }
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
+ /* Get volume value string from VCONF */
+ if (vconf_get_int(g_volume_vconf[i], &val) < 0) {
+ AUDIO_LOG_ERROR("vconf_get_int(%s) failed", g_volume_vconf[i]);
+ continue;
+ }
+
+ AUDIO_LOG_INFO("read vconf. %s = %d", g_volume_vconf[i], val);
+ ah->volume.volume_level[i] = val;
+ }
+
+ if (!(ah->volume.volume_value_table = malloc(AUDIO_VOLUME_DEVICE_MAX * sizeof(audio_volume_value_table_s)))) {
+ AUDIO_LOG_ERROR("volume_value_table malloc failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ audio_ret = __load_volume_value_table_from_ini(ah);
+ if (audio_ret != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("gain table load error");
+ return AUDIO_ERR_UNDEFINED;
+ }
+
+ return audio_ret;
+}
+
+audio_return_e _audio_volume_deinit(audio_hal_s *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ if (ah->volume.volume_value_table) {
+ free(ah->volume.volume_value_table);
+ ah->volume.volume_value_table = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_get_volume_level_max(void *audio_handle, audio_volume_info_s *info, uint32_t *level)
+{
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(level, AUDIO_ERR_PARAMETER);
+
+ /* Get max volume level by device & type */
+ *level = ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)];
+
+ AUDIO_LOG_DEBUG("get_[%s] volume_level_max: %d", info->type, *level);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_get_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t *level)
+{
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(level, AUDIO_ERR_PARAMETER);
+
+ if (!strncmp(info->type, "master", strlen("master"))) {
+ *level = g_master_volume_level;
+ return AUDIO_RET_OK;
+ }
+
+ *level = ah->volume.volume_level[__get_volume_idx_by_string_type(info->type)];
+
+ AUDIO_LOG_INFO("get [%s] volume_level: %d, direction(%d)", info->type, *level, info->direction);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_get_volume_value(void *audio_handle, audio_volume_info_s *info, uint32_t level, double *value)
+{
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+ audio_volume_value_table_s *volume_value_table;
+ char dump_str[AUDIO_DUMP_STR_LEN] = {0,};
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->volume.volume_value_table, AUDIO_ERR_PARAMETER);
+
+ /* Get basic volume by device & type & level */
+ volume_value_table = ah->volume.volume_value_table;
+ if (ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)] < level)
+ *value = VOLUME_VALUE_MAX;
+ else
+ *value = volume_value_table->volume[__get_volume_idx_by_string_type(info->type)][level];
+ *value *= volume_value_table->gain[AUDIO_GAIN_TYPE_DEFAULT]; /* need to fix getting gain via audio_info_t */
+
+ AUDIO_LOG_DEBUG("get_volume_value:%d(%s)=>%f %s", level, info->type, *value, &dump_str[0]);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_e audio_set_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t level)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ if (!strncmp(info->type, "master", strlen("master"))) {
+ g_master_volume_level = level;
+ return AUDIO_RET_OK;
+ }
+ AUDIO_RETURN_VAL_IF_FAIL((ah->volume.volume_level_max[__get_volume_idx_by_string_type(info->type)] >= level), AUDIO_ERR_PARAMETER);
+
+ /* Update volume level */
+ ah->volume.volume_level[__get_volume_idx_by_string_type(info->type)] = level;
+ AUDIO_LOG_INFO("set [%s] volume_level: %d, direction(%d)", info->type, level, info->direction);
+
+ /* set mixer related to H/W volume if needed */
+
+ return audio_ret;
+}
+
+audio_return_e audio_get_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t *mute)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(mute, AUDIO_ERR_PARAMETER);
+
+ /* TODO. Not implemented */
+
+ return audio_ret;
+}
+
+audio_return_e audio_set_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t mute)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+
+ /* TODO. Not implemented */
+
+ return audio_ret;
+}
+
+audio_return_e audio_set_volume_ratio(void *audio_handle, audio_stream_info_s *info, double ratio)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("set [%s] volume_ratio: %f, direction(%u), index(%u)", info->role, ratio, info->direction, info->idx);
+
+ /* TODO. Not implemented */
+
+ return audio_ret;
+}
+
+audio_return_e audio_notify_ducking_activation_changed(void *audio_handle, audio_ducking_info_s *info, uint32_t is_activated)
+{
+ audio_return_e audio_ret = AUDIO_RET_OK;
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info->target_role, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, duration:%u, ratio:%lf, is_activated:%u", info->target_role, info->duration, info->ratio, is_activated);
+
+ /* TODO. Not implemented */
+
+ return audio_ret;
+}
diff --git a/tizen-audio.c b/tizen-audio.c
new file mode 100644
index 0000000..0ca97a7
--- /dev/null
+++ b/tizen-audio.c
@@ -0,0 +1,90 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+audio_return_e audio_init(void **audio_handle)
+{
+ audio_hal_s *ah;
+ audio_return_e ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+
+ if (!(ah = calloc(1, sizeof(audio_hal_s)))) {
+ AUDIO_LOG_ERROR("failed to alloc()");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((ret = _audio_ctrl_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_ctrl_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+ if ((ret = _audio_volume_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_volume_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+ if ((ret = _audio_routing_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_routing_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+ if ((ret = _audio_stream_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_stream_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+ if ((ret = _audio_pcm_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_pcm_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+ if ((ret = _audio_comm_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_comm_init(), ret(0x%x)", ret);
+ goto error_exit;
+ }
+
+ *audio_handle = (void *)ah;
+ return AUDIO_RET_OK;
+
+error_exit:
+ if (ah)
+ free(ah);
+
+ return ret;
+}
+
+audio_return_e audio_deinit(void *audio_handle)
+{
+ audio_hal_s *ah = (audio_hal_s *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ _audio_volume_deinit(ah);
+ _audio_routing_deinit(ah);
+ _audio_stream_deinit(ah);
+ _audio_pcm_deinit(ah);
+ _audio_comm_deinit(ah);
+ _audio_ctrl_deinit(ah);
+
+ free(ah);
+ ah = NULL;
+
+ return AUDIO_RET_OK;
+}
diff --git a/tizen-audio.h b/tizen-audio.h
new file mode 100644
index 0000000..a1c2546
--- /dev/null
+++ b/tizen-audio.h
@@ -0,0 +1,431 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2022 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 footizenaudiofoo
+#define footizenaudiofoo
+
+#include <stdint.h>
+#include <hal/hal-audio-interface.h>
+
+/**
+ * @file tizen-audio.h
+ * @brief This file contains the Audio Hardware Abstraction Layer Interfaces.
+ */
+
+/**
+ * @addtogroup TIZEN_AUDIO_HAL_MODULE
+ * @{
+ */
+
+/**
+ * @brief Initializes audio hal.
+ * @since_tizen 3.0
+ * @param[out] audio_handle The audio hal handle
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_deinit()
+ */
+audio_return_e audio_init(void **audio_handle);
+
+/**
+ * @brief De-initializes audio hal.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_init()
+ */
+audio_return_e audio_deinit(void *audio_handle);
+
+/**
+ * @brief Gets the maximum volume level supported for a particular volume information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[out] level The maximum volume level
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_set_volume_level()
+ * @see audio_get_volume_level()
+ * @see audio_get_volume_value()
+ */
+audio_return_e audio_get_volume_level_max(void *audio_handle, audio_volume_info_s *info, uint32_t *level);
+
+/**
+ * @brief Gets the volume level specified for a particular volume information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[out] level The current volume level
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_set_volume_level()
+ * @see audio_get_volume_level_max()
+ * @see audio_get_volume_value()
+ */
+audio_return_e audio_get_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t *level);
+
+/**
+ * @brief Sets the volume level specified for a particular volume information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[in] level The volume level to be set
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_get_volume_level()
+ * @see audio_get_volume_level_max()
+ * @see audio_get_volume_value()
+ */
+audio_return_e audio_set_volume_level(void *audio_handle, audio_volume_info_s *info, uint32_t level);
+
+/**
+ * @brief Gets the volume value specified for a particular volume information and level.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[in] level The volume level
+ * @param[out] value The volume value (range is from 0.0 to 1.0 inclusive, 1.0 = 100%)
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_set_volume_level()
+ * @see audio_get_volume_level()
+ * @see audio_get_volume_level_max()
+ */
+audio_return_e audio_get_volume_value(void *audio_handle, audio_volume_info_s *info, uint32_t level, double *value);
+
+/**
+ * @brief Gets the volume mute specified for a particular volume information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[out] mute The volume mute state : (@c 0 = unmute, @c 1 = mute)
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_set_volume_mute()
+ */
+audio_return_e audio_get_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t *mute);
+
+/**
+ * @brief Sets the volume mute specified for a particular volume information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[in] mute The volume mute state to be set : (@c 0 = unmute, @c 1 = mute)
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_get_volume_mute()
+ */
+audio_return_e audio_set_volume_mute(void *audio_handle, audio_volume_info_s *info, uint32_t mute);
+
+/**
+ * @brief Sets the volume ratio specified for a particular volume information. (optional)
+ * @since_tizen 5.5
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio volume information
+ * @param[in] ratio The volume ratio to be set (Min.:0.0 ~ Max.:1.0, default:1.0)
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ */
+audio_return_e audio_set_volume_ratio(void *audio_handle, audio_stream_info_s *info, double ratio);
+
+/**
+ * @brief Gets notified when a ducking is activated and deactivated.
+ * @since_tizen 5.5
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The ducking information including target role, duration and ratio
+ * @param[in] is_activated The activation state (@c true = activated, @c false = deactivated)
+ *
+ * @remarks This information can be used for volume controls.
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ */
+audio_return_e audio_notify_ducking_activation_changed(void *audio_handle, audio_ducking_info_s *info, uint32_t is_activated);
+
+/**
+ * @brief Updates the audio routing according to audio route information.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The audio route information including role and devices
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_update_route_option()
+ */
+audio_return_e audio_update_route(void *audio_handle, audio_route_info_s *info);
+
+/**
+ * @brief Updates audio routing option according to audio route option.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] option The option that can be used for audio routing including role, name and value
+ *
+ * @remarks This option can be used for audio routing.\n
+ * It is recommended to apply this option for routing per each role.
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_update_route()
+ */
+audio_return_e audio_update_route_option(void *audio_handle, audio_route_option_s *option);
+
+/**
+ * @brief Gets notified when a stream is connected and disconnected.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] info The stream information including role, direction, index
+ * @param[in] is_connected The connection state of this stream (@c true = connected, @c false = disconnected)
+ *
+ * @remarks This information can be used for audio routing, volume controls and so on.
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ */
+audio_return_e audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_s *info, uint32_t is_connected);
+
+/**
+ * @brief Opens a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] card The card of PCM
+ * @param[in] device The device of PCM
+ * @param[in] direction The direction of PCM
+ * @param[in] sample_spec The sample specification
+ * @param[in] period_size The period size
+ * @param[in] periods The periods
+ * @param[out] pcm_handle The PCM handle
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_close()
+ */
+audio_return_e audio_pcm_open(void *audio_handle, const char *card, const char *device, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods, void **pcm_handle);
+
+/**
+ * @brief Starts a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle to be started
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_avail()
+ * @see audio_pcm_write()
+ * @see audio_pcm_read()
+ * @see audio_pcm_stop()
+ * @see audio_pcm_recover()
+ */
+audio_return_e audio_pcm_start(void *audio_handle, void *pcm_handle);
+
+/**
+ * @brief Stops a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle to be stopped
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_start()
+ */
+audio_return_e audio_pcm_stop(void *audio_handle, void *pcm_handle);
+
+/**
+ * @brief Closes a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle to be closed
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_open()
+ */
+audio_return_e audio_pcm_close(void *audio_handle, void *pcm_handle);
+
+/**
+ * @brief Gets available number of frames.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[out] avail The available number of frames
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_write()
+ * @see audio_pcm_read()
+ */
+audio_return_e audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail);
+
+/**
+ * @brief Writes frames to a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[in] buffer The buffer containing frames
+ * @param[in] frames The number of frames to be written
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_avail()
+ * @see audio_pcm_recover()
+ */
+audio_return_e audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames);
+
+/**
+ * @brief Reads frames from a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[out] buffer The buffer containing frames
+ * @param[in] frames The number of frames to be read
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_avail()
+ * @see audio_pcm_recover()
+ */
+audio_return_e audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames);
+
+/**
+ * @brief Gets poll descriptor for a PCM handle.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[out] fd The poll descriptor
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_open()
+ * @see audio_pcm_recover()
+ */
+audio_return_e audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd);
+
+/**
+ * @brief Recovers the PCM state.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[in] revents The returned event from pollfd
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_start()
+ * @see audio_pcm_write()
+ * @see audio_pcm_read()
+ * @see audio_pcm_get_fd()
+ */
+audio_return_e audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents);
+
+/**
+ * @brief Gets parameters of a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[in] direction The direction of PCM
+ * @param[out] sample_spec The sample specification
+ * @param[out] period_size The period size
+ * @param[out] periods The periods
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_set_params()
+ */
+audio_return_e audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+
+/**
+ * @brief Sets hardware and software parameters of a PCM device.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] pcm_handle The PCM handle
+ * @param[in] direction The direction of PCM
+ * @param[in] sample_spec The sample specification
+ * @param[in] period_size The period size
+ * @param[in] periods The periods
+ *
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #AUDIO_RET_OK Success
+ * @see audio_pcm_set_params()
+ */
+audio_return_e audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+
+/**
+ * @brief Adds the message callback function.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] message_cb The message callback function
+ * @param[in] user_data The user data passed to the callback function
+ *
+ * @see message_cb()
+ * @see audio_remove_message_cb()
+ */
+audio_return_e audio_add_message_cb(void *audio_handle, message_cb callback, void *user_data);
+
+/**
+ * @brief Removes the message callback function.
+ * @since_tizen 3.0
+ * @param[in] audio_handle The audio hal handle
+ * @param[in] message_cb The message callback function to be removed
+ *
+ * @see message_cb()
+ * @see audio_add_message_cb()
+ */
+audio_return_e audio_remove_message_cb(void *audio_handle, message_cb callback);
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+#endif