summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeungbae Shin <seungbae.shin@samsung.com>2019-01-08 17:39:04 +0900
committerSeungbae Shin <seungbae.shin@samsung.com>2019-01-08 17:44:00 +0900
commit348a5c758f4bdbeb9d12f26a091c6f2527d9706e (patch)
tree33441f05543e533f5fe616b7102e3266b7930aa5
parentb06afa8f8940a551cc036a0e4bab31205fcae0bc (diff)
downloadaudio-hal-exynos9110-348a5c758f4bdbeb9d12f26a091c6f2527d9706e.tar.gz
audio-hal-exynos9110-348a5c758f4bdbeb9d12f26a091c6f2527d9706e.tar.bz2
audio-hal-exynos9110-348a5c758f4bdbeb9d12f26a091c6f2527d9706e.zip
Base import from audio-hal-wm1831-tw2 and modifiy default alsa card name for exynos9110 [Version] 0.1.0 [Issue Type] Bring-Up Change-Id: I71ac3d01293a846715b82fca8a76e60e6db08c46
-rw-r--r--LICENSE.Apache-2.0202
-rw-r--r--Makefile.am21
-rw-r--r--NOTICE3
-rw-r--r--audio-hal-exynos9110.manifest5
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac60
-rw-r--r--packaging/audio-hal-exynos9110.spec48
-rw-r--r--tizen-audio-comm.c117
-rw-r--r--tizen-audio-ctrl.c46
-rw-r--r--tizen-audio-impl-ctrl.c251
-rw-r--r--tizen-audio-impl-pcm.c1042
-rw-r--r--tizen-audio-impl-ucm.c663
-rw-r--r--tizen-audio-impl.h66
-rw-r--r--tizen-audio-internal.h327
-rw-r--r--tizen-audio-pcm.c196
-rw-r--r--tizen-audio-routing.c594
-rw-r--r--tizen-audio-stream.c54
-rw-r--r--tizen-audio-util.c80
-rw-r--r--tizen-audio-volume.c415
-rw-r--r--tizen-audio.c90
-rw-r--r--tizen-audio.h523
21 files changed, 4813 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..98494e4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,21 @@
+lib_LTLIBRARIES = libtizen-audio.la
+
+libtizen_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-ucm.c \
+ tizen-audio-impl-ctrl.c
+libtizen_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
+libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS) $(EXPAT_LIBS)
+libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) $(EXPAT_CFLAGS) -DUSE_DLOG
+
+if USE_TINYALSA
+libtizen_audio_la_LIBADD += $(TINYALSA_LIBS)
+libtizen_audio_la_CFLAGS += $(TINYALSA_CFLAGS) -D__USE_TINYALSA__
+endif
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/audio-hal-exynos9110.manifest b/audio-hal-exynos9110.manifest
new file mode 100644
index 0000000..86dbb26
--- /dev/null
+++ b/audio-hal-exynos9110.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
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..abb8e4a
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,60 @@
+AC_PREREQ([2.67])
+
+AC_INIT([audio-hal-exynos9110], [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)
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+
+
+AC_CONFIG_FILES([ \
+ Makefile
+ ])
+AC_OUTPUT
diff --git a/packaging/audio-hal-exynos9110.spec b/packaging/audio-hal-exynos9110.spec
new file mode 100644
index 0000000..1f137ec
--- /dev/null
+++ b/packaging/audio-hal-exynos9110.spec
@@ -0,0 +1,48 @@
+Name: audio-hal-exynos9110
+Summary: TIZEN Audio HAL for Exynos9110(TW3)
+Version: 0.1.0
+Release: 0
+Group: System/Libraries
+License: Apache-2.0
+URL: http://tizen.org
+Source0: audio-hal-exynos9110-%{version}.tar.gz
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(iniparser)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(alsa)
+#BuildRequires: pkgconfig(tinyalsa)
+Provides: libtizen-audio.so
+
+%description
+TIZEN Audio HAL for Exynos9110(TW3)
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE -DSYSCONFDIR=\\\"%{_sysconfdir}\\\""
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+
+export USE_TINYALSA="0"
+
+%autogen
+%configure
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest audio-hal-exynos9110.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libtizen-audio.so
+%license LICENSE.Apache-2.0
diff --git a/tizen-audio-comm.c b/tizen-audio-comm.c
new file mode 100644
index 0000000..628e8d9
--- /dev/null
+++ b/tizen-audio-comm.c
@@ -0,0 +1,117 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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_t __set_message_callback(audio_hal_t *ah, message_cb callback, void *user_data)
+{
+ audio_return_t 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_t __unset_message_callback(audio_hal_t *ah)
+{
+ audio_return_t 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_t _audio_comm_init(audio_hal_t *ah)
+{
+ audio_return_t 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_t _audio_comm_deinit(audio_hal_t *ah)
+{
+ audio_return_t 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_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value)
+{
+ audio_return_t 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_t audio_add_message_cb(void *audio_handle, message_cb callback, void *user_data)
+{
+ audio_return_t 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_t *)audio_handle, callback, user_data);
+
+ return ret;
+}
+
+audio_return_t audio_remove_message_cb(void *audio_handle, message_cb callback)
+{
+ audio_return_t 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_t *)audio_handle);
+
+ return ret;
+} \ No newline at end of file
diff --git a/tizen-audio-ctrl.c b/tizen-audio-ctrl.c
new file mode 100644
index 0000000..2b9bacd
--- /dev/null
+++ b/tizen-audio-ctrl.c
@@ -0,0 +1,46 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2018 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_t _audio_ctrl_init(audio_hal_t *ah)
+{
+ audio_return_t 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_t _audio_ctrl_deinit(audio_hal_t *ah)
+{
+ audio_return_t 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..1c54bc4
--- /dev/null
+++ b/tizen-audio-impl-ctrl.c
@@ -0,0 +1,251 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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_t _mixer_control_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_init(&(ah->mixer.mutex), NULL);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _mixer_control_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_destroy(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _mixer_control_set_param(audio_hal_t *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_t _mixer_control_get_value(audio_hal_t *ah, 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);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, ALSA_DEFAULT_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_t _mixer_control_set_value(audio_hal_t *ah, 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(ctl_name, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", ALSA_DEFAULT_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_t _mixer_control_set_value_string(audio_hal_t *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_t _mixer_control_get_element(audio_hal_t *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;
+} \ No newline at end of file
diff --git a/tizen-audio-impl-pcm.c b/tizen-audio-impl-pcm.c
new file mode 100644
index 0000000..a859a1e
--- /dev/null
+++ b/tizen-audio-impl-pcm.c
@@ -0,0 +1,1042 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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 <stdbool.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_t format)
+{
+ return g_format_convert_table[format];
+}
+
+/* #define DEBUG_TIMING */
+
+static int __pcm_device_set_params(audio_hal_t *ah, snd_pcm_t *pcm, uint32_t samplerate, uint32_t channels)
+{
+ snd_pcm_hw_params_t *params = NULL;
+ int err = 0;
+ unsigned int val = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ /* 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(&params);
+
+ /* Fill it in with default values. */
+ if (snd_pcm_hw_params_any(pcm, params) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Set the desired hardware parameters. */
+ /* Interleaved mode */
+ err = snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+ err = snd_pcm_hw_params_set_rate(pcm, params, samplerate, 0);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+ err = snd_pcm_hw_params_set_channels(pcm, params, channels);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+ err = snd_pcm_hw_params(pcm, params);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Dump current param */
+ snd_pcm_hw_params_get_access(params, (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(params, (snd_pcm_format_t*)&val);
+ AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
+ snd_pcm_format_name((snd_pcm_format_t)val),
+ snd_pcm_format_description((snd_pcm_format_t)val));
+
+ snd_pcm_hw_params_get_subformat(params, (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(params, &val);
+ AUDIO_LOG_DEBUG("channels = %d\n", val);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+#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_t *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
+
+static audio_return_t __pcm_device_open(audio_hal_t *ah, audio_pcm_devices_t *pcm_devices, const char *device, uint32_t direction, uint32_t samplerate, uint32_t channels)
+{
+ int err, ret = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+#ifdef __USE_TINYALSA__
+ AUDIO_LOG_WARN("need implementation for tinyAlsa");
+ return AUDIO_ERR_NOT_IMPLEMENTED;
+#else
+ AUDIO_LOG_INFO("Setup DAI PCM");
+
+ if (direction & AUDIO_DEVICE_DIRECTION_IN) {
+ /* Capture PCM */
+ if ((err = snd_pcm_open((snd_pcm_t **)&pcm_devices->in, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", device, snd_strerror(err));
+ ret = AUDIO_ERR_IOCTL;
+ goto error;
+ }
+ ret = __pcm_device_set_params(ah, pcm_devices->in, samplerate, channels);
+ if (ret != 0) {
+ AUDIO_LOG_ERROR("capture DAI PCM(%s, %p) setparam failure", device, pcm_devices->in);
+ ret = AUDIO_ERR_INTERNAL;
+ goto error;
+ }
+ AUDIO_LOG_INFO("capture DAI PCM(%s, %p) open/setparam success", device, pcm_devices->in);
+ }
+
+ if (direction & AUDIO_DEVICE_DIRECTION_OUT) {
+ /* Playback PCM */
+ if ((err = snd_pcm_open((snd_pcm_t **)&pcm_devices->out, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", device, snd_strerror(err));
+ ret = AUDIO_ERR_IOCTL;
+ goto error;
+ }
+ ret = __pcm_device_set_params(ah, pcm_devices->out, samplerate, channels);
+ if (ret != 0) {
+ AUDIO_LOG_ERROR("playback DAI PCM(%s, %p) setparam failure", device, pcm_devices->out);
+ ret = AUDIO_ERR_INTERNAL;
+ goto error;
+ }
+ AUDIO_LOG_INFO("playback DAI PCM(%s, %p) open/setparam success", device, pcm_devices->out);
+ }
+#endif
+
+ return AUDIO_RET_OK;
+
+error:
+ if ((direction & AUDIO_DEVICE_DIRECTION_OUT) && pcm_devices->out) {
+ snd_pcm_close(pcm_devices->out);
+ pcm_devices->out = NULL;
+ }
+ if ((direction & AUDIO_DEVICE_DIRECTION_IN) && pcm_devices->in) {
+ snd_pcm_close(pcm_devices->in);
+ pcm_devices->in = NULL;
+ }
+ return ret;
+}
+
+audio_return_t _voice_pcm_open_all(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return __pcm_device_open(ah, &ah->device.voice_pcm, VOICE_PCM_DEVICE,
+ AUDIO_DEVICE_DIRECTION_IN | AUDIO_DEVICE_DIRECTION_OUT, 48000, 2);
+}
+
+audio_return_t _bt_pcm_open_all(audio_hal_t *ah)
+{
+ uint32_t samplerate;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ samplerate = (ah->device.bt_wideband) ? 16000 : 8000;
+
+ return __pcm_device_open(ah, &ah->device.bt_pcm, BT_PCM_DEVICE,
+ AUDIO_DEVICE_DIRECTION_IN | AUDIO_DEVICE_DIRECTION_OUT, samplerate, 1);
+}
+
+bool _is_voice_pcm_opened_all(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ if (ah->device.voice_pcm.in && ah->device.voice_pcm.out)
+ return true;
+ else
+ return false;
+}
+
+bool _is_bt_pcm_opened_all(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ if (ah->device.bt_pcm.in && ah->device.bt_pcm.out)
+ return true;
+ else
+ return false;
+}
+
+audio_return_t _voice_pcm_close_all(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("close voice pcm handles");
+
+ if (ah->device.voice_pcm.out) {
+ if ((audio_ret = _pcm_close(ah->device.voice_pcm.out)))
+ AUDIO_LOG_ERROR("failed to _pcm_close() for voice pcm out, ret(0x%x)", audio_ret);
+ else {
+ ah->device.voice_pcm.out = NULL;
+ AUDIO_LOG_INFO("voice pcm out handle close success");
+ }
+ }
+ if (ah->device.voice_pcm.in) {
+ if ((audio_ret = _pcm_close(ah->device.voice_pcm.in)))
+ AUDIO_LOG_ERROR("failed to _pcm_close() for voice pcm in, ret(0x%x)", audio_ret);
+ else {
+ ah->device.voice_pcm.in = NULL;
+ AUDIO_LOG_INFO("voice pcm in handle close success");
+ }
+ }
+
+ return audio_ret;
+}
+
+audio_return_t _bt_pcm_close_all(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("close bt pcm handles");
+
+ if (ah->device.bt_pcm.out) {
+ if ((audio_ret = _pcm_close(ah->device.bt_pcm.out)))
+ AUDIO_LOG_ERROR("failed to _pcm_close() for bt pcm out, ret(0x%x)", audio_ret);
+ else {
+ ah->device.bt_pcm.out = NULL;
+ AUDIO_LOG_INFO("bt pcm out handle close success");
+ }
+ }
+ if (ah->device.bt_pcm.in) {
+ if ((audio_ret = _pcm_close(ah->device.bt_pcm.in)))
+ AUDIO_LOG_ERROR("failed to _pcm_close() for bt pcm in, ret(0x%x)", audio_ret);
+ else {
+ ah->device.bt_pcm.in = NULL;
+ AUDIO_LOG_INFO("bt pcm in handle close success");
+ }
+ }
+
+ return audio_ret;
+}
+
+void _reset_pcm_devices(audio_hal_t *ah)
+{
+ AUDIO_RETURN_IF_FAIL(ah);
+
+ _voice_pcm_close_all(ah);
+ _bt_pcm_close_all(ah);
+}
+
+#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_t _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_t *ss;
+
+ ss = (audio_pcm_sample_spec_t *)sample_spec;
+ ss->format = __convert_format((audio_sample_format_t)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_t 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_t _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_t _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_t _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_t _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_t _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_t _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_t _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_t _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_t _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_t *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_t *)*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_t *ss;
+ int dir;
+ snd_pcm_uframes_t _period_size, _buffer_size;
+ snd_pcm_format_t _format;
+ unsigned int _rate, _channels;
+ snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
+ unsigned int _periods;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = (audio_pcm_sample_spec_t *)*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);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _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_t ss;
+ snd_pcm_uframes_t _buffer_size;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = *(audio_pcm_sample_spec_t *)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_t)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, period_size / 2)) < 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, 1024)) < 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_t _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size)
+{
+ audio_return_t 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_t _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-ucm.c b/tizen-audio-impl-ucm.c
new file mode 100644
index 0000000..7ff7cbc
--- /dev/null
+++ b/tizen-audio-impl-ucm.c
@@ -0,0 +1,663 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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>
+#ifdef ALSA_UCM_DEBUG_TIME
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+#ifdef ALSA_UCM_DEBUG_TIME
+#define SND_USE_CASE_SET __set_use_case_with_time
+#else
+#define SND_USE_CASE_SET snd_use_case_set
+#endif
+
+#define UCM_PREFIX_CURRENT ">>> UCM current"
+#define UCM_PREFIX_REQUESTED "> UCM requested"
+#define UCM_PREFIX_CHANGED "<<< UCM changed"
+
+#define DUMP_LEN 512
+
+static void __dump_use_case(const char* prefix, const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count)
+{
+ int i;
+ dump_data_t* dump = NULL;
+
+ if (!(dump = _audio_dump_new(DUMP_LEN))) {
+ AUDIO_LOG_ERROR("Failed to create dump string...");
+ return;
+ }
+
+ /* Verb */
+ _audio_dump_add_str(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
+
+ /* Devices */
+ if (devices) {
+ for (i = 0; i < dev_count; i++) {
+ _audio_dump_add_str(dump, (i != dev_count - 1) ? "%s, " : "%s", devices[i]);
+ }
+ }
+ _audio_dump_add_str(dump, " ] Modifier [ ");
+
+ /* Modifiers */
+ if (modifiers) {
+ for (i = 0; i < mod_count; i++) {
+ _audio_dump_add_str(dump, (i != mod_count - 1) ? "%s, " : "%s", modifiers[i]);
+ }
+ }
+ _audio_dump_add_str(dump, " ]");
+
+ AUDIO_LOG_INFO("TEST %s : %s", prefix, _audio_dump_get_str(dump));
+
+ _audio_dump_free(dump);
+}
+
+#ifdef ALSA_UCM_DEBUG_TIME
+static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
+{
+ int ret = 0;
+ struct timeval t_start, t_stop;
+ unsigned long long t_diff = 0;
+
+ gettimeofday(&t_start, NULL);
+ ret = snd_use_case_set(uc_mgr, identifier, value);
+ gettimeofday(&t_stop, NULL);
+ if (t_start.tv_sec < t_stop.tv_sec)
+ t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
+ t_diff += (t_stop.tv_usec - t_start.tv_usec);
+ AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
+
+ return ret;
+}
+#endif
+
+audio_return_t _ucm_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
+
+ if (!ah->ucm.uc_mgr) {
+ AUDIO_LOG_ERROR("uc_mgr open failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _ucm_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+
+ if (ah->ucm.uc_mgr) {
+ snd_use_case_mgr_close(ah->ucm.uc_mgr);
+ ah->ucm.uc_mgr = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+/* UCM sequence
+ 1) If verb is null or verb is not changed
+ 1-1) If device is changed
+ (If there is request for same device, it will be ignored)
+ -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
+ (playback/capture device will be enabled again if there is no request for playback/capture device)
+ 1-2) If device is not changed
+ 1-2-1) If modifier is changed
+ (If there is request for same modifier, it will be ignored)
+ -> Disable modifiers, enable modifiers
+ 2) If verb is changed
+ -> Reset, set new verb, enable devices & modifiers
+ */
+audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[])
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
+ const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
+ int old_dev_count = 0, dev_count = 0;
+ int old_mod_count = 0, mod_count = 0;
+ const char **dis_dev_list = NULL, **ena_dev_list = NULL;
+ const char **dis_mod_list = NULL, **ena_mod_list = NULL;
+ int dis_dev_count = 0, ena_dev_count = 0;
+ int dis_mod_count = 0, ena_mod_count = 0;
+ int i = 0, j = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
+ old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
+ old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
+ __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count);
+
+ if (devices) {
+ for (dev_count = 0; devices[dev_count]; dev_count++);
+ }
+ if (modifiers) {
+ for (mod_count = 0; modifiers[mod_count]; mod_count++);
+ }
+
+ __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, modifiers, mod_count);
+
+ if (old_verb && streq(verb, old_verb)) {
+ AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
+
+ if (old_dev_count > 0) {
+ dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
+ for (i = 0; i < old_dev_count; i++) {
+ dis_dev_list[i] = NULL;
+ }
+ }
+ if (dev_count > 0) {
+ ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
+ for (i = 0; i < dev_count; i++) {
+ ena_dev_list[i] = NULL;
+ }
+ }
+ if (old_mod_count > 0) {
+ dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
+ for (i = 0; i < old_mod_count; i++) {
+ dis_mod_list[i] = NULL;
+ }
+ }
+ if (mod_count > 0) {
+ ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
+ for (i = 0; i < mod_count; i++) {
+ ena_mod_list[i] = NULL;
+ }
+ }
+
+ /* update disable modifiers list which are not present in new modifier list */
+ for (i = 0; i < old_mod_count; i++) {
+ int need_disable_mod = 1;
+
+ for (j = 0; j < mod_count; j++) {
+ if (streq(old_mod_list[i], modifiers[j])) {
+ need_disable_mod = 0;
+ break;
+ }
+ }
+ if (need_disable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ dis_mod_list[dis_mod_count++] = old_mod_list[i];
+ }
+ }
+
+ /* update disable devices list which are not present in new device list */
+ for (i = 0; i < old_dev_count; i++) {
+ int need_disable_dev = 1;
+
+ for (j = 0; j < dev_count; j++) {
+ if (streq(old_dev_list[i], devices[j])) {
+ need_disable_dev = 0;
+ break;
+ }
+ }
+ if (need_disable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ dis_dev_list[dis_dev_count++] = old_dev_list[i];
+ }
+ }
+
+ /* update enable devices list which are not present in old device list */
+ for (i = 0; i < dev_count; i++) {
+ int need_enable_dev = 1;
+
+ for (j = 0; j < old_dev_count; j++) {
+ if (streq(devices[i], old_dev_list[j])) {
+ need_enable_dev = 0;
+ break;
+ }
+ }
+ if (need_enable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ ena_dev_list[ena_dev_count++] = devices[i];
+ }
+ }
+
+ /* update enable modifiers list which are not present in old modifier list */
+ for (i = 0; i < mod_count; i++) {
+ int need_enable_mod = 1;
+
+ for (j = 0; j < old_mod_count; j++) {
+ if (streq(modifiers[i], old_mod_list[j])) {
+ need_enable_mod = 0;
+ break;
+ }
+ }
+ if (need_enable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ ena_mod_list[ena_mod_count++] = modifiers[i];
+ }
+ }
+
+ /* disable modifiers */
+ for (i = 0; i < dis_mod_count; i++) {
+ AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
+ }
+
+ /* disable devices */
+ for (i = 0; i < dis_dev_count; i++) {
+ AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
+ }
+
+ /* enable devices */
+ for (i = 0; i < ena_dev_count; i++) {
+ AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
+ }
+
+ /* enable modifiers */
+ for (i = 0; i < ena_mod_count; i++) {
+ AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
+ }
+ } else {
+ is_verb_changed = 1;
+
+ AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
+ /* set new verb */
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
+ AUDIO_LOG_ERROR("Setting verb %s failed", verb);
+ audio_ret = AUDIO_ERR_UNDEFINED;
+ goto exit;
+ }
+ /* enable devices */
+ for (i = 0; i < dev_count; i++) {
+ AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
+ }
+ /* enable modifiers */
+ for (i = 0; i < mod_count; i++) {
+ AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
+ }
+ }
+
+exit:
+ if (old_verb)
+ free((void *)old_verb);
+ if (old_dev_list)
+ snd_use_case_free_list(old_dev_list, old_dev_count);
+ if (old_mod_list)
+ snd_use_case_free_list(old_mod_list, old_mod_count);
+ if (dis_dev_list)
+ free((void *)dis_dev_list);
+ if (ena_dev_list)
+ free((void *)ena_dev_list);
+ if (dis_mod_list)
+ free((void *)dis_mod_list);
+ if (ena_mod_list)
+ free((void *)ena_mod_list);
+
+ if (is_verb_changed == 1 || is_dev_changed == 1 || is_mod_changed == 1) {
+ const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
+ int new_dev_count = 0, new_mod_count = 0;
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
+ new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
+ new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
+ __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count);
+
+ if (new_verb)
+ free((void *)new_verb);
+ if (new_dev_list)
+ snd_use_case_free_list(new_dev_list, new_dev_count);
+ if (new_mod_list)
+ snd_use_case_free_list(new_mod_list, new_mod_count);
+ }
+
+ return audio_ret;
+}
+
+audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[])
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int is_verb_changed = 0, is_dev_changed = 0;
+ const char *old_verb = NULL, **old_dev_list = NULL;
+ int old_dev_count = 0, dev_count = 0;
+ const char **dis_dev_list = NULL, **ena_dev_list = NULL;
+ int dis_dev_count = 0, ena_dev_count = 0;
+ int i = 0, j = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
+ old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
+ __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, NULL, 0);
+
+ if (devices) {
+ if (streq(verb, "Voice")) {
+ /* In case of Voice verb with Bluetooth device, make this device alone */
+ for (dev_count = 0; devices[dev_count]; dev_count++) {
+ if (streq(devices[dev_count], "Bluetooth")) {
+ devices = &devices[dev_count];
+ dev_count = 1;
+ AUDIO_LOG_DEBUG("Voice verb with Bluetooth device only");
+ break;
+ }
+ }
+ } else {
+ for (dev_count = 0; devices[dev_count]; dev_count++);
+ }
+ }
+
+ __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, NULL, 0);
+
+ if (old_verb && streq(verb, old_verb)) {
+ AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
+
+ if (old_dev_count > 0) {
+ dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
+ for (i = 0; i < old_dev_count; i++) {
+ dis_dev_list[i] = NULL;
+ }
+ }
+ if (dev_count > 0) {
+ ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
+ for (i = 0; i < dev_count; i++) {
+ ena_dev_list[i] = NULL;
+ }
+ }
+
+ /* update disable devices list which are not present in new device list */
+ for (i = 0; i < old_dev_count; i++) {
+ int need_disable_dev = 1;
+
+ for (j = 0; j < dev_count; j++) {
+ if (streq(old_dev_list[i], devices[j])) {
+ need_disable_dev = 0;
+ break;
+ }
+ }
+ if (need_disable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ dis_dev_list[dis_dev_count++] = old_dev_list[i];
+ }
+ }
+
+ /* update enable devices list which are not present in old device list */
+ for (i = 0; i < dev_count; i++) {
+ int need_enable_dev = 1;
+
+ for (j = 0; j < old_dev_count; j++) {
+ if (streq(devices[i], old_dev_list[j])) {
+ need_enable_dev = 0;
+ break;
+ }
+ }
+ if (need_enable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ ena_dev_list[ena_dev_count++] = devices[i];
+ }
+ }
+
+ /* disable devices */
+ for (i = 0; i < dis_dev_count; i++) {
+ AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
+ }
+
+ /* enable devices */
+ for (i = 0; i < ena_dev_count; i++) {
+ AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
+ }
+
+ } else {
+ is_verb_changed = 1;
+
+ AUDIO_LOG_INFO("Setting new verb: %s", verb);
+ /* set new verb */
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
+ AUDIO_LOG_ERROR("Setting verb %s failed", verb);
+ audio_ret = AUDIO_ERR_UNDEFINED;
+ goto exit;
+ }
+ /* enable devices */
+ for (i = 0; i < dev_count; i++) {
+ AUDIO_LOG_INFO("Enable device : %s", devices[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
+ }
+ }
+
+exit:
+ if (old_verb)
+ free((void *)old_verb);
+ if (old_dev_list)
+ snd_use_case_free_list(old_dev_list, old_dev_count);
+ if (dis_dev_list)
+ free((void *)dis_dev_list);
+ if (ena_dev_list)
+ free((void *)ena_dev_list);
+
+ if (is_verb_changed == 1 || is_dev_changed == 1) {
+ const char *new_verb = NULL, **new_dev_list = NULL;
+ int new_dev_count = 0;
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
+ new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
+ __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, NULL, 0);
+
+ if (new_verb)
+ free((void *)new_verb);
+ if (new_dev_list)
+ snd_use_case_free_list(new_dev_list, new_dev_count);
+ }
+
+ return audio_ret;
+
+}
+
+audio_return_t _ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[])
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int is_verb_changed = 0, is_mod_changed = 0;
+ const char *old_verb = NULL, **old_mod_list = NULL;
+ int old_mod_count = 0, mod_count = 0;
+ const char **dis_mod_list = NULL, **ena_mod_list = NULL;
+ int dis_mod_count = 0, ena_mod_count = 0;
+ int i = 0, j = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(modifiers, AUDIO_ERR_PARAMETER);
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
+ old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
+ __dump_use_case(UCM_PREFIX_CURRENT, old_verb, NULL, 0, old_mod_list, old_mod_count);
+
+ if (modifiers) {
+ for (mod_count = 0; modifiers[mod_count]; mod_count++);
+ }
+
+ __dump_use_case(UCM_PREFIX_REQUESTED, verb, NULL, 0, modifiers, mod_count);
+
+ if (old_verb && streq(verb, old_verb)) {
+ AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
+
+ if (old_mod_count > 0) {
+ dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
+ for (i = 0; i < old_mod_count; i++) {
+ dis_mod_list[i] = NULL;
+ }
+ }
+ if (mod_count > 0) {
+ ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
+ for (i = 0; i < mod_count; i++) {
+ ena_mod_list[i] = NULL;
+ }
+ }
+
+ /* update disable modifiers list which are not present in new modifier list */
+ for (i = 0; i < old_mod_count; i++) {
+ int need_disable_mod = 1;
+
+ for (j = 0; j < mod_count; j++) {
+ if (streq(old_mod_list[i], modifiers[j])) {
+ need_disable_mod = 0;
+ break;
+ }
+ }
+ if (need_disable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ dis_mod_list[dis_mod_count++] = old_mod_list[i];
+ }
+ }
+
+ /* update enable modifiers list which are not present in old modifier list */
+ for (i = 0; i < mod_count; i++) {
+ int need_enable_mod = 1;
+
+ for (j = 0; j < old_mod_count; j++) {
+ if (streq(modifiers[i], old_mod_list[j])) {
+ need_enable_mod = 0;
+ break;
+ }
+ }
+ if (need_enable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ ena_mod_list[ena_mod_count++] = modifiers[i];
+ }
+ }
+
+ /* disable modifiers */
+ for (i = 0; i < dis_mod_count; i++) {
+ AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
+ }
+
+ /* enable modifiers */
+ for (i = 0; i < ena_mod_count; i++) {
+ AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
+ }
+ } else {
+ is_verb_changed = 1;
+
+ AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
+ /* set new verb */
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
+ AUDIO_LOG_ERROR("Setting verb %s failed", verb);
+ audio_ret = AUDIO_ERR_UNDEFINED;
+ goto exit;
+ }
+ /* enable modifiers */
+ for (i = 0; i < mod_count; i++) {
+ AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
+ if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
+ }
+ }
+
+exit:
+ if (old_verb)
+ free((void *)old_verb);
+ if (old_mod_list)
+ snd_use_case_free_list(old_mod_list, old_mod_count);
+ if (dis_mod_list)
+ free((void *)dis_mod_list);
+ if (ena_mod_list)
+ free((void *)ena_mod_list);
+
+ if (is_verb_changed == 1 || is_mod_changed == 1) {
+ const char *new_verb = NULL, **new_mod_list = NULL;
+ int new_mod_count = 0;
+
+ snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
+ new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
+ __dump_use_case(UCM_PREFIX_CHANGED, new_verb, NULL, 0, new_mod_list, new_mod_count);
+
+ if (new_verb)
+ free((void *)new_verb);
+ if (new_mod_list)
+ snd_use_case_free_list(new_mod_list, new_mod_count);
+ }
+
+ return audio_ret;
+}
+
+audio_return_t _ucm_get_verb(audio_hal_t *ah, const char **value)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
+
+ if ((ret = snd_use_case_get(ah->ucm.uc_mgr, "_verb", value)) < 0) {
+ AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
+ ret = AUDIO_ERR_UNDEFINED;
+ }
+
+ return ret;
+}
+
+audio_return_t _ucm_reset_use_case(audio_hal_t *ah)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
+
+ if ((ret = snd_use_case_set(ah->ucm.uc_mgr, "_verb", AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
+ AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
+ ret = AUDIO_ERR_UNDEFINED;
+ }
+
+ return ret;
+}
diff --git a/tizen-audio-impl.h b/tizen-audio-impl.h
new file mode 100644
index 0000000..8218032
--- /dev/null
+++ b/tizen-audio-impl.h
@@ -0,0 +1,66 @@
+#ifndef footizenaudioimplfoo
+#define footizenaudioimplfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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 <stdbool.h>
+
+/* PCM */
+audio_return_t _voice_pcm_open_all(audio_hal_t *ah);
+audio_return_t _voice_pcm_close_all(audio_hal_t *ah);
+audio_return_t _bt_pcm_open_all(audio_hal_t *ah);
+audio_return_t _bt_pcm_close_all(audio_hal_t *ah);
+bool _is_voice_pcm_opened_all(audio_hal_t *ah);
+bool _is_bt_pcm_opened_all(audio_hal_t *ah);
+void _reset_pcm_devices(audio_hal_t *ah);
+audio_return_t _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_t _pcm_start(void *pcm_handle);
+audio_return_t _pcm_stop(void *pcm_handle);
+audio_return_t _pcm_close(void *pcm_handle);
+audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail);
+audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames);
+audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames);
+audio_return_t _pcm_get_fd(void *pcm_handle, int *fd);
+audio_return_t _pcm_recover(void *pcm_handle, int revents);
+audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_t _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event);
+audio_return_t _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size);
+
+/* Control */
+audio_return_t _mixer_control_init(audio_hal_t *ah);
+audio_return_t _mixer_control_deinit(audio_hal_t *ah);
+audio_return_t _mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
+audio_return_t _mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val);
+audio_return_t _mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value);
+audio_return_t _mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val);
+audio_return_t _mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem);
+
+/* UCM */
+audio_return_t _ucm_init(audio_hal_t *ah);
+audio_return_t _ucm_deinit(audio_hal_t *ah);
+#define _ucm_update_use_case _ucm_set_use_case
+audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[]);
+audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[]);
+audio_return_t _ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[]);
+audio_return_t _ucm_get_verb(audio_hal_t *ah, const char **value);
+audio_return_t _ucm_reset_use_case(audio_hal_t *ah);
+
+#endif
diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h
new file mode 100644
index 0000000..5d3ab1d
--- /dev/null
+++ b/tizen-audio-internal.h
@@ -0,0 +1,327 @@
+#ifndef footizenaudiointernalfoo
+#define footizenaudiointernalfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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 <stdbool.h>
+#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)
+/*
+static device_type_t outDeviceTypes[] = {
+ { AUDIO_DEVICE_OUT_SPEAKER, "speaker" },
+ { AUDIO_DEVICE_OUT_BT_SCO, "bt-sco-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_8K_NB, "bt-8k-sco-nb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_16K_NB, "bt-16k-sco-nb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_8K_WB, "bt-8k-sco-wb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_16K_WB, "bt-16k-sco-wb-headset" },
+ { 0, 0 },
+};
+
+static device_type_t inDeviceTypes[] = {
+ { AUDIO_DEVICE_IN_MAIN_MIC, "main-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO, "bt-sco-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_8K_NB, "bt-8k-sco-nb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_16K_NB, "bt-16k-sco-nb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_8K_WB, "bt-8k-sco-wb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_16K_WB, "bt-16k-sco-wb-mic" },
+ { 0, 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_BT_SCO_8K_NB = AUDIO_DEVICE_OUT | 0x00000010,
+ AUDIO_DEVICE_OUT_BT_SCO_16K_NB = AUDIO_DEVICE_OUT | 0x00000020,
+ AUDIO_DEVICE_OUT_BT_SCO_8K_WB = AUDIO_DEVICE_OUT | 0x00000040,
+ AUDIO_DEVICE_OUT_BT_SCO_16K_WB = AUDIO_DEVICE_OUT | 0x00000080,
+ AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_RECEIVER |
+ AUDIO_DEVICE_OUT_JACK |
+ AUDIO_DEVICE_OUT_BT_SCO |
+ AUDIO_DEVICE_OUT_BT_SCO_8K_NB |
+ AUDIO_DEVICE_OUT_BT_SCO_16K_NB |
+ AUDIO_DEVICE_OUT_BT_SCO_8K_WB |
+ AUDIO_DEVICE_OUT_BT_SCO_16K_WB),
+ /* 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_BT_SCO_8K_NB = AUDIO_DEVICE_IN | 0x00000010,
+ AUDIO_DEVICE_IN_BT_SCO_16K_NB = AUDIO_DEVICE_IN | 0x00000020,
+ AUDIO_DEVICE_IN_BT_SCO_8K_WB = AUDIO_DEVICE_IN | 0x00000040,
+ AUDIO_DEVICE_IN_BT_SCO_16K_WB = AUDIO_DEVICE_IN | 0x00000080,
+ AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_MAIN_MIC |
+ AUDIO_DEVICE_IN_SUB_MIC |
+ AUDIO_DEVICE_IN_JACK |
+ AUDIO_DEVICE_IN_BT_SCO |
+ AUDIO_DEVICE_IN_BT_SCO_8K_NB |
+ AUDIO_DEVICE_IN_BT_SCO_16K_NB |
+ AUDIO_DEVICE_IN_BT_SCO_8K_WB |
+ AUDIO_DEVICE_IN_BT_SCO_16K_WB),
+};
+
+typedef struct device_type {
+ uint32_t type;
+ const char *name;
+} device_type_t;
+
+/* Verbs */
+#define AUDIO_USE_CASE_VERB_INACTIVE "Inactive"
+#define AUDIO_USE_CASE_VERB_HIFI "HiFi"
+#define AUDIO_USE_CASE_VERB_VOICECALL "Voice"
+#define AUDIO_USE_CASE_VERB_VOIP "VoIP"
+
+#define streq !strcmp
+#define strneq strcmp
+
+#define ALSA_DEFAULT_CARD "Exynos9110Sound"
+
+/* DAI PCM DEVICE */
+#define VOICE_PCM_DEVICE "hw:0,1"
+#define BT_PCM_DEVICE "hw:0,2"
+
+#define MAX_DEVICES 5
+#define MAX_NAME_LEN 32
+
+/* type definitions */
+typedef signed char int8_t;
+
+/* PCM */
+typedef struct {
+ snd_pcm_format_t format;
+ uint32_t rate;
+ uint8_t channels;
+} audio_pcm_sample_spec_t;
+
+/* Routing */
+typedef enum audio_route_mode {
+ VERB_NORMAL,
+ VERB_VOICECALL,
+ VERB_VOIP,
+} audio_route_mode_t;
+
+typedef struct {
+ snd_pcm_t *in;
+ snd_pcm_t *out;
+} audio_pcm_devices_t;
+
+typedef struct audio_hal_device {
+ uint32_t active_in;
+ uint32_t active_out;
+ audio_pcm_devices_t voice_pcm;
+ audio_pcm_devices_t bt_pcm;
+ audio_route_mode_t mode;
+ bool bt_wideband;
+ bool bt_sco_ready;
+} audio_hal_device_t;
+
+/* 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_t;
+
+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_t;
+
+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_t;
+
+enum {
+ AUDIO_DEVICE_DIRECTION_IN = 0x01,
+ AUDIO_DEVICE_DIRECTION_OUT = 0x02
+};
+
+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_t *volume_value_table;
+} audio_hal_volume_t;
+
+/* UCM */
+typedef struct audio_hal_ucm {
+ snd_use_case_mgr_t* uc_mgr;
+} audio_hal_ucm_t;
+
+/* 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_t;
+
+/* 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_t;
+
+typedef struct audio_hal_comm {
+ message_cb msg_cb;
+ void *user_data;
+} audio_hal_comm_t;
+
+/* Overall */
+#define MAX_DIRECTION 2
+typedef struct audio_hal {
+ audio_hal_device_t device;
+ audio_hal_volume_t volume;
+ audio_hal_ucm_t ucm;
+ audio_hal_mixer_t mixer;
+ audio_hal_comm_t comm;
+ audio_route_info_t *saved_route_infos[MAX_DIRECTION];
+ bool call_wideband;
+} audio_hal_t;
+
+audio_return_t _audio_ctrl_init(audio_hal_t *ah);
+audio_return_t _audio_ctrl_deinit(audio_hal_t *ah);
+audio_return_t _audio_volume_init(audio_hal_t *ah);
+audio_return_t _audio_volume_deinit(audio_hal_t *ah);
+audio_return_t _audio_routing_init(audio_hal_t *ah);
+audio_return_t _audio_routing_deinit(audio_hal_t *ah);
+audio_return_t _audio_stream_init(audio_hal_t *ah);
+audio_return_t _audio_stream_deinit(audio_hal_t *ah);
+audio_return_t _audio_pcm_init(audio_hal_t *ah);
+audio_return_t _audio_pcm_deinit(audio_hal_t *ah);
+audio_return_t _audio_comm_init(audio_hal_t *ah);
+audio_return_t _audio_comm_deinit(audio_hal_t *ah);
+audio_return_t _audio_comm_send_message(audio_hal_t *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..556be06
--- /dev/null
+++ b/tizen-audio-pcm.c
@@ -0,0 +1,196 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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_t _audio_pcm_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.voice_pcm.in = NULL;
+ ah->device.voice_pcm.out = NULL;
+ ah->device.bt_pcm.in = NULL;
+ ah->device.bt_pcm.out = NULL;
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_pcm_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t 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_t 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 > 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;
+
+ AUDIO_LOG_INFO("Opening PCM handle %p", *pcm_handle);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_start(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t 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_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t 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_t audio_pcm_close(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t 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);
+
+ if ((audio_ret = _pcm_close(pcm_handle)))
+ return audio_ret;
+
+ pcm_handle = NULL;
+
+ AUDIO_LOG_INFO("PCM handle close success");
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
+{
+ audio_return_t 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_t audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
+{
+ audio_return_t 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_t audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
+{
+ audio_return_t 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_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
+{
+ audio_return_t 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_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
+{
+ audio_return_t 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_t 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_t 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_t 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_t 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..96528f6
--- /dev/null
+++ b/tizen-audio-routing.c
@@ -0,0 +1,594 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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_t outDeviceTypes[] = {
+ { AUDIO_DEVICE_OUT_SPEAKER, "speaker" },
+ { AUDIO_DEVICE_OUT_BT_SCO, "bt-sco-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_8K_NB, "bt-8k-sco-nb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_16K_NB, "bt-16k-sco-nb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_8K_WB, "bt-8k-sco-wb-headset" },
+ { AUDIO_DEVICE_OUT_BT_SCO_16K_WB, "bt-16k-sco-wb-headset" },
+ { 0, 0 },
+};
+
+static device_type_t inDeviceTypes[] = {
+ { AUDIO_DEVICE_IN_MAIN_MIC, "main-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO, "bt-sco-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_8K_NB, "bt-8k-sco-nb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_16K_NB, "bt-16k-sco-nb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_8K_WB, "bt-8k-sco-wb-mic" },
+ { AUDIO_DEVICE_IN_BT_SCO_16K_WB, "bt-16k-sco-wb-mic" },
+ { 0, 0 },
+};
+
+static const char* mode_to_verb_str[] = {
+ AUDIO_USE_CASE_VERB_HIFI,
+ AUDIO_USE_CASE_VERB_VOICECALL,
+ AUDIO_USE_CASE_VERB_VOIP,
+};
+
+static bool __is_acive_device_bt_sco_for_call(audio_hal_t *ah)
+{
+ if (!ah) {
+ AUDIO_LOG_WARN("ah is null");
+ return false;
+ }
+
+ if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO_8K_NB &&
+ ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO_8K_NB)
+ return true;
+ if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO_16K_NB &&
+ ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO_16K_NB)
+ return true;
+ if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO_8K_WB &&
+ ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO_8K_WB)
+ return true;
+ if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO_16K_WB &&
+ ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO_16K_WB)
+ return true;
+
+ return false;
+}
+
+static uint32_t __convert_device_string_to_enum(audio_hal_t *ah, const char *verb, const char* device_str, uint32_t direction)
+{
+ uint32_t device = 0;
+
+ AUDIO_LOG_INFO("verb(%s), device string(%s), direction(%d)", verb, device_str, direction);
+
+ if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+
+ } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ if (!strncmp(verb, AUDIO_USE_CASE_VERB_HIFI, MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_BT_SCO;
+ } else if (!strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, MAX_NAME_LEN)) {
+ AUDIO_LOG_INFO("device.bt_widband(%d), call_wideband(%d)", ah->device.bt_wideband, ah->call_wideband);
+ if (ah->device.bt_wideband) {
+ if (ah->call_wideband)
+ device = AUDIO_DEVICE_OUT_BT_SCO_16K_WB;
+ else
+ device = AUDIO_DEVICE_OUT_BT_SCO_16K_NB;
+ } else {
+ if (ah->call_wideband)
+ device = AUDIO_DEVICE_OUT_BT_SCO_8K_WB;
+ else
+ device = AUDIO_DEVICE_OUT_BT_SCO_8K_NB;
+ }
+ } else {
+ device = AUDIO_DEVICE_OUT_BT_SCO;
+ AUDIO_LOG_WARN("invalid verb, set device(%d) forcedly", device);
+ }
+
+ } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
+ device = AUDIO_DEVICE_IN_MAIN_MIC;
+
+ } else if ((!strncmp(device_str, "bt-sco", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ if (!strncmp(verb, AUDIO_USE_CASE_VERB_HIFI, MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_IN_BT_SCO;
+ } else if (!strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, MAX_NAME_LEN)) {
+ AUDIO_LOG_INFO("device.bt_widband(%d), call_wideband(%d)", ah->device.bt_wideband, ah->call_wideband);
+ if (ah->device.bt_wideband) {
+ if (ah->call_wideband)
+ device = AUDIO_DEVICE_IN_BT_SCO_16K_WB;
+ else
+ device = AUDIO_DEVICE_IN_BT_SCO_16K_NB;
+ } else {
+ if (ah->call_wideband)
+ device = AUDIO_DEVICE_IN_BT_SCO_8K_WB;
+ else
+ device = AUDIO_DEVICE_IN_BT_SCO_8K_NB;
+ }
+ } else {
+ device = AUDIO_DEVICE_IN_BT_SCO;
+ AUDIO_LOG_WARN("invalid verb, set device(%d) forcedly", device);
+ }
+
+ } else {
+ device = AUDIO_DEVICE_NONE;
+ }
+
+ AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
+ return device;
+}
+
+static audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
+{
+ audio_return_t 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(ah, verb, 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;
+ }
+
+ audio_ret = _ucm_set_devices(ah, verb, active_devices);
+ if (audio_ret)
+ AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
+
+ return audio_ret;
+}
+
+static audio_return_t __save_route_infos(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ int i = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ for (i = 0; i < MAX_DIRECTION; i++) {
+ if (!ah->saved_route_infos[i]) {
+ ah->saved_route_infos[i] = malloc(sizeof(audio_route_info_t));
+ memset(ah->saved_route_infos[i], 0, sizeof(audio_route_info_t));
+
+ ah->saved_route_infos[i]->device_infos = malloc(sizeof(device_info_t));
+ memcpy(ah->saved_route_infos[i]->device_infos, devices, sizeof(device_info_t));
+
+ ah->saved_route_infos[i]->num_of_devices = num_of_devices;
+
+ AUDIO_LOG_INFO("SAVE route infos[%d]: device_infos->type[%s],id[%u]",
+ i, ah->saved_route_infos[i]->device_infos->type, ah->saved_route_infos[i]->device_infos->id);
+ return AUDIO_RET_OK;
+ }
+ }
+
+ AUDIO_LOG_ERROR("could not find empty slot to save route infos");
+ return AUDIO_ERR_INTERNAL;
+}
+
+static void __reset_saved_route_infos(void *audio_handle)
+{
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+ int i = 0;
+
+ AUDIO_RETURN_IF_FAIL(ah);
+
+ for (i = 0; i < MAX_DIRECTION; i++) {
+ if (ah->saved_route_infos[i]) {
+ if (ah->saved_route_infos[i]->device_infos)
+ free(ah->saved_route_infos[i]->device_infos);
+ free(ah->saved_route_infos[i]);
+ ah->saved_route_infos[i] = NULL;
+ AUDIO_LOG_INFO("reset saved route infos[%d] well", i);
+ }
+ }
+}
+
+static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ device_info_t *devices = NULL;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
+
+ if (ah->device.mode != VERB_NORMAL) {
+ _reset_pcm_devices(ah);
+ ah->device.mode = VERB_NORMAL;
+ }
+
+ devices = route_info->device_infos;
+
+ AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
+
+ audio_ret = __set_devices(ah, verb, 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_t __update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_VOICECALL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voicecall++");
+
+ if (!strncmp(devices[0].type, "bt-sco", MAX_NAME_LEN))
+ if (!ah->device.bt_sco_ready)
+ return __save_route_infos(ah, devices, num_of_devices);
+
+ if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ if (ah->device.mode != VERB_VOICECALL) {
+ ah->device.mode = VERB_VOICECALL;
+ _reset_pcm_devices(ah);
+ } else {
+ /* if this request is for BT SCO device */
+ if (__is_acive_device_bt_sco_for_call(ah)) {
+ if (_is_bt_pcm_opened_all(ah)) {
+ AUDIO_LOG_INFO("bt pcm device is already opened, skip it");
+ return audio_ret;
+ }
+ if ((audio_ret = _bt_pcm_open_all(ah))) {
+ AUDIO_LOG_ERROR("Failed to open bt pcm device: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ }
+
+ if (_is_voice_pcm_opened_all(ah)) {
+ AUDIO_LOG_INFO("voice pcm device is already opened, skip it");
+ return audio_ret;
+ }
+ if ((audio_ret = _voice_pcm_open_all(ah))) {
+ AUDIO_LOG_ERROR("Failed to open voice pcm device: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ }
+
+ return audio_ret;
+}
+
+static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voip++");
+
+ if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ /* FIXME. If necessary, set VERB_VOIP */
+ ah->device.mode = VERB_NORMAL;
+
+ /* TO DO: Set modifiers */
+ return audio_ret;
+}
+
+static audio_return_t __update_route_voice_recognition(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voice_recognition++");
+
+ if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ if (ah->device.mode != VERB_NORMAL) {
+ ah->device.mode = VERB_NORMAL;
+ _reset_pcm_devices(ah);
+ }
+
+ /* if this request is for BT SCO device */
+ if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO) {
+ if (_is_bt_pcm_opened_all(ah)) {
+ AUDIO_LOG_INFO("bt pcm device is already opened, skip it");
+ return audio_ret;
+ }
+
+ if ((audio_ret = _bt_pcm_open_all(ah))) {
+ AUDIO_LOG_ERROR("Failed to open bt pcm device: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ }
+
+ return audio_ret;
+}
+
+static audio_return_t __update_route_voice_information(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voice_information++");
+
+ audio_ret = __set_devices(ah, verb, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ if (ah->device.mode != VERB_NORMAL) {
+ ah->device.mode = VERB_NORMAL;
+ _reset_pcm_devices(ah);
+ }
+ /* if this request is for BT SCO device */
+ if (ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+ if (_is_bt_pcm_opened_all(ah)) {
+ AUDIO_LOG_INFO("bt pcm device is already opened, skip it");
+ return audio_ret;
+ }
+
+ if ((audio_ret = _bt_pcm_open_all(ah))) {
+ AUDIO_LOG_ERROR("Failed to open bt pcm device: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ }
+
+ return audio_ret;
+}
+
+static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
+{
+ audio_return_t 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 (ah->device.mode == VERB_VOICECALL) {
+ if ((audio_ret = _bt_pcm_close_all(ah)))
+ AUDIO_LOG_ERROR("failed to _bt_pcm_close(), ret(0x%x)", audio_ret);
+ if ((audio_ret = _voice_pcm_close_all(ah)))
+ AUDIO_LOG_ERROR("failed to _voice_pcm_close(), ret(0x%x)", audio_ret);
+ if (!ah->device.active_in && !ah->device.active_out)
+ ah->device.mode = VERB_NORMAL;
+ } else if (ah->device.mode == VERB_NORMAL) {
+ if (direction == AUDIO_DIRECTION_IN) {
+ /* voice-recognition case */
+ if ((audio_ret = _bt_pcm_close_all(ah)))
+ AUDIO_LOG_ERROR("failed to _bt_pcm_close(), ret(0x%x)", audio_ret);
+ }
+ }
+
+ __reset_saved_route_infos(ah);
+
+ if (active_devices[0] == NULL) {
+ AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
+ return AUDIO_RET_OK;
+ }
+
+ if ((audio_ret = _ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices)))
+ AUDIO_LOG_ERROR("failed to _ucm_set_devices(), ret(0x%x)", audio_ret);
+
+ /* reset bandwidth information */
+ ah->device.bt_wideband = false;
+ ah->call_wideband = false;
+ ah->device.bt_sco_ready = false;
+
+ return audio_ret;
+}
+
+audio_return_t _audio_routing_init(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.active_in = 0x0;
+ ah->device.active_out = 0x0;
+ ah->device.mode = VERB_NORMAL;
+
+ if ((audio_ret = _ucm_init(ah)))
+ AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
+
+ return audio_ret;
+}
+
+audio_return_t _audio_routing_deinit(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _ucm_deinit(ah)))
+ AUDIO_LOG_ERROR("failed to _ucm_deinit(), ret(0x%x)", audio_ret);
+
+ return audio_ret;
+}
+
+audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+ device_info_t *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("call-voice", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_voicecall(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voicecall route return 0x%x", audio_ret);
+
+ } else 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("voice-recognition", info->role, MAX_NAME_LEN) ||
+ !strncmp("voice-recognition-service", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_voice_recognition(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voice-recognition route return 0x%x", audio_ret);
+
+ } else if (!strncmp("voice-information", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_voice_information(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voice-information 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 {
+ /* need to prepare for "alarm","notification","emergency","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_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)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);
+
+ if (!strncmp("bt-wideband", option->name, MAX_NAME_LEN)) {
+ ah->device.bt_wideband = (option->value > 0) ? true : false;
+ } else if (!strncmp("call-wideband", option->name, MAX_NAME_LEN)) {
+ ah->call_wideband = (option->value > 0) ? true : false;
+ } else if (!strncmp("bt-sco-ready", option->name, MAX_NAME_LEN)) {
+ ah->device.bt_sco_ready = (option->value > 0) ? true : false;
+ if (ah->device.bt_sco_ready) {
+ int i = 0;
+ for (i = 0; i < MAX_DIRECTION; i++) {
+ if (ah->saved_route_infos[i]) {
+ if ((audio_ret = __update_route_voicecall(ah, ah->saved_route_infos[i]->device_infos, ah->saved_route_infos[i]->num_of_devices)))
+ AUDIO_LOG_WARN("update voicecall route from SAVED return 0x%x", audio_ret);
+ }
+ }
+ }
+ __reset_saved_route_infos(ah);
+ } else {
+ AUDIO_LOG_WARN("undefined route option");
+ }
+
+ return audio_ret;
+}
diff --git a/tizen-audio-stream.c b/tizen-audio-stream.c
new file mode 100644
index 0000000..c60a443
--- /dev/null
+++ b/tizen-audio-stream.c
@@ -0,0 +1,54 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 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_t _audio_stream_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_stream_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)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..6ab4aa0
--- /dev/null
+++ b/tizen-audio-util.c
@@ -0,0 +1,80 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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..87c5523
--- /dev/null
+++ b/tizen-audio-volume.c
@@ -0,0 +1,415 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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 <stdbool.h>
+#include <string.h>
+#include <math.h>
+#include <vconf.h>
+#include <iniparser.h>
+
+#include "tizen-audio-internal.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)
+
+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_t *ah)
+{
+ audio_volume_value_table_t *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_t __load_volume_value_table_from_ini(audio_hal_t *ah)
+{
+ dictionary * dict = NULL;
+ uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
+ audio_volume_value_table_t *volume_value_table = ah->volume.volume_value_table;
+ int size = 0;
+
+ 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;
+ }
+ }
+
+ const char delimiter[] = ", ";
+ char *key, *list_str, *token, *ptr = NULL;
+ const char *table_str = "volumes";
+
+ /* 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);
+ list_str = iniparser_getstring(dict, key, NULL);
+ 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);
+ }
+ } 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);
+ token = iniparser_getstring(dict, key, NULL);
+ if (token) {
+ volume_value_table->gain[gain_type_idx] = atof(token);
+ } 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_t _audio_volume_init(audio_hal_t *ah)
+{
+ int i;
+ int val = 0;
+ audio_return_t 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_t)))) {
+ 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_t _audio_volume_deinit(audio_hal_t *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_t audio_get_volume_level_max(void *audio_handle, audio_volume_info_t *info, uint32_t *level)
+{
+ audio_hal_t *ah = (audio_hal_t *)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_t audio_get_volume_level(void *audio_handle, audio_volume_info_t *info, uint32_t *level)
+{
+ audio_hal_t *ah = (audio_hal_t *)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_t audio_get_volume_value(void *audio_handle, audio_volume_info_t *info, uint32_t level, double *value)
+{
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+ audio_volume_value_table_t *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_t audio_set_volume_level(void *audio_handle, audio_volume_info_t *info, uint32_t level)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)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_t audio_get_volume_mute(void *audio_handle, audio_volume_info_t *info, uint32_t *mute)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)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_t audio_set_volume_mute(void *audio_handle, audio_volume_info_t *info, uint32_t mute)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)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;
+}
diff --git a/tizen-audio.c b/tizen-audio.c
new file mode 100644
index 0000000..c587ee0
--- /dev/null
+++ b/tizen-audio.c
@@ -0,0 +1,90 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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_t audio_init(void **audio_handle)
+{
+ audio_hal_t *ah;
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+
+ if (!(ah = malloc(sizeof(audio_hal_t)))) {
+ AUDIO_LOG_ERROR("failed to malloc()");
+ 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_t audio_deinit(void *audio_handle)
+{
+ audio_hal_t *ah = (audio_hal_t *)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;
+} \ No newline at end of file
diff --git a/tizen-audio.h b/tizen-audio.h
new file mode 100644
index 0000000..94efa03
--- /dev/null
+++ b/tizen-audio.h
@@ -0,0 +1,523 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2015 - 2016 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>
+
+/**
+ * @file tizen-audio.h
+ * @brief This file contains the Audio Hardware Abstraction Layer Interfaces.
+ */
+
+/**
+ * @addtogroup TIZEN_AUDIO_HAL_MODULE
+ * @{
+ */
+
+/**
+ * @brief Enumeration for return codes.
+ * @since_tizen 3.0
+ */
+typedef enum audio_return {
+ AUDIO_RET_OK = 0,
+ AUDIO_ERR_UNDEFINED = (int32_t)0x80001000,
+ AUDIO_ERR_RESOURCE = (int32_t)0x80001001,
+ AUDIO_ERR_PARAMETER = (int32_t)0x80001002,
+ AUDIO_ERR_IOCTL = (int32_t)0x80001003,
+ AUDIO_ERR_INVALID_STATE = (int32_t)0x80001004,
+ AUDIO_ERR_INTERNAL = (int32_t)0x80001005,
+ /* add new enemerator here */
+ AUDIO_ERR_NOT_IMPLEMENTED = (int32_t)0x80001100,
+} audio_return_t ;
+
+/**
+ * @brief Enumeration for audio direction.
+ * @since_tizen 3.0
+ */
+typedef enum audio_direction {
+ AUDIO_DIRECTION_IN, /**< Capture */
+ AUDIO_DIRECTION_OUT, /**< Playback */
+} audio_direction_t;
+
+/**
+ * @brief Device information including type, direction and id.
+ * @since_tizen 3.0
+ */
+typedef struct device_info {
+ const char *type;
+ uint32_t direction;
+ uint32_t id;
+} device_info_t;
+
+/**
+ * @brief Volume information including type, gain and direction.
+ * @since_tizen 3.0
+ */
+typedef struct audio_volume_info {
+ const char *type;
+ const char *gain;
+ uint32_t direction;
+} audio_volume_info_t ;
+
+/**
+ * @brief Route information including role and device.
+ * @since_tizen 3.0
+ */
+typedef struct audio_route_info {
+ const char *role;
+ device_info_t *device_infos;
+ uint32_t num_of_devices;
+} audio_route_info_t;
+
+/**
+ * @brief Route option including role, name and value.
+ * @since_tizen 3.0
+ */
+typedef struct audio_route_option {
+ const char *role;
+ const char *name;
+ int32_t value;
+} audio_route_option_t;
+
+/**
+ * @brief Stream information including role, direction and index.
+ * @since_tizen 3.0
+ */
+typedef struct audio_stream_info {
+ const char *role;
+ uint32_t direction;
+ uint32_t idx;
+} audio_stream_info_t ;
+
+/**
+ * @brief Called when audio hal implementation needs to send a message.
+ * @since_tizen 3.0
+ * @param[in] name The message name
+ * @param[in] value The message value
+ * @param[in] user_data The user data passed from the callback registration function
+ *
+ * @see audio_add_message_cb()
+ * @see audio_remove_message_cb()
+ */
+typedef void (*message_cb)(const char *name, int value, void *user_data);
+
+/* Overall */
+typedef struct audio_interface {
+ /* Initialization & de-initialization */
+ audio_return_t (*init)(void **audio_handle);
+ audio_return_t (*deinit)(void *audio_handle);
+ /* Volume */
+ audio_return_t (*get_volume_level_max)(void *audio_handle, audio_volume_info_t *info, uint32_t *level);
+ audio_return_t (*get_volume_level)(void *audio_handle, audio_volume_info_t *info, uint32_t *level);
+ audio_return_t (*set_volume_level)(void *audio_handle, audio_volume_info_t *info, uint32_t level);
+ audio_return_t (*get_volume_value)(void *audio_handle, audio_volume_info_t *info, uint32_t level, double *value);
+ audio_return_t (*get_volume_mute)(void *audio_handle, audio_volume_info_t *info, uint32_t *mute);
+ audio_return_t (*set_volume_mute)(void *audio_handle, audio_volume_info_t *info, uint32_t mute);
+ /* Routing */
+ audio_return_t (*update_route)(void *audio_handle, audio_route_info_t *info);
+ audio_return_t (*update_route_option)(void *audio_handle, audio_route_option_t *option);
+ /* Stream */
+ audio_return_t (*notify_stream_connection_changed)(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected);
+ /* PCM */
+ audio_return_t (*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_t (*pcm_start)(void *audio_handle, void *pcm_handle);
+ audio_return_t (*pcm_stop)(void *audio_handle, void *pcm_handle);
+ audio_return_t (*pcm_close)(void *audio_handle, void *pcm_handle);
+ audio_return_t (*pcm_avail)(void *audio_handle, void *pcm_handle, uint32_t *avail);
+ audio_return_t (*pcm_write)(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames);
+ audio_return_t (*pcm_read)(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames);
+ audio_return_t (*pcm_get_fd)(void *audio_handle, void *pcm_handle, int *fd);
+ audio_return_t (*pcm_recover)(void *audio_handle, void *pcm_handle, int revents);
+ audio_return_t (*pcm_get_params)(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+ audio_return_t (*pcm_set_params)(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+ /* Message callback */
+ audio_return_t (*add_message_cb)(void *audio_handle, message_cb callback, void *user_data);
+ audio_return_t (*remove_message_cb)(void *audio_handle, message_cb callback);
+} audio_interface_t;
+
+/**
+ * @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_t 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_t 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_t audio_get_volume_level_max(void *audio_handle, audio_volume_info_t *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_t audio_get_volume_level(void *audio_handle, audio_volume_info_t *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_t audio_set_volume_level(void *audio_handle, audio_volume_info_t *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_t audio_get_volume_value(void *audio_handle, audio_volume_info_t *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_t audio_get_volume_mute(void *audio_handle, audio_volume_info_t *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_t audio_set_volume_mute(void *audio_handle, audio_volume_info_t *info, uint32_t mute);
+
+/**
+ * @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_t audio_update_route(void *audio_handle, audio_route_info_t *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_t audio_update_route_option(void *audio_handle, audio_route_option_t *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_t audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_t *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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t 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_t audio_remove_message_cb(void *audio_handle, message_cb callback);
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+#endif