summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSangchul Lee <sc11.lee@samsung.com>2015-11-19 19:34:33 +0900
committerSangchul Lee <sc11.lee@samsung.com>2015-11-23 12:05:06 +0900
commit6595a75f3bbc0bcd91d57cf331212a6c9869f546 (patch)
tree4f6014df612c38575613a6fbd1d38d7a1b5ccd9a
parent8b9000b7a827d925b8a9d7f13ec1121688f2f58a (diff)
downloadaudio-hal-sc7727-6595a75f3bbc0bcd91d57cf331212a6c9869f546.tar.gz
audio-hal-sc7727-6595a75f3bbc0bcd91d57cf331212a6c9869f546.tar.bz2
audio-hal-sc7727-6595a75f3bbc0bcd91d57cf331212a6c9869f546.zip
Initialization audio HAL for SC7727 (target:TM1)
Codes are based on audio-hal-wm5110(0.2.12) :76790ab397edc43e9529550dfee2879a1e5ff5a3 [Version] 0.1.0 [Profile] Mobile [Issue Type] Initialization Change-Id: I35cd6c2132dd839d1973721a279834daf4bd352c Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
-rw-r--r--LICENSE.Apache-2.0202
-rw-r--r--Makefile.am17
-rw-r--r--NOTICE3
-rw-r--r--audio-hal-sc7727.manifest5
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac60
-rw-r--r--packaging/audio-hal-sc7727.spec50
-rw-r--r--tizen-audio-device.c1037
-rw-r--r--tizen-audio-internal.h247
-rw-r--r--tizen-audio-ucm.c718
-rw-r--r--tizen-audio-util.c427
-rw-r--r--tizen-audio-volume.c398
-rw-r--r--tizen-audio.c263
-rw-r--r--tizen-audio.h236
14 files changed, 3673 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..1145f10
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,17 @@
+lib_LTLIBRARIES = libtizen-audio.la
+
+libtizen_audio_la_SOURCES = tizen-audio.c \
+ tizen-audio-device.c \
+ tizen-audio-volume.c \
+ tizen-audio-ucm.c \
+ tizen-audio-util.c
+libtizen_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
+if USE_TINYALSA
+libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(TINYALSA_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS)
+libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(TINYALSA_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) -D__USE_TINYALSA__
+else
+libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS)
+libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS)
+endif
+libtizen_audio_la_CFLAGS += -DUSE_DLOG
+
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-sc7727.manifest b/audio-hal-sc7727.manifest
new file mode 100644
index 0000000..a76fdba
--- /dev/null
+++ b/audio-hal-sc7727.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..3b0c487
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,60 @@
+AC_PREREQ([2.67])
+
+AC_INIT([audio-hal-sc7727], [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-sc7727.spec b/packaging/audio-hal-sc7727.spec
new file mode 100644
index 0000000..ac15050
--- /dev/null
+++ b/packaging/audio-hal-sc7727.spec
@@ -0,0 +1,50 @@
+Name: audio-hal-sc7727
+Summary: TIZEN Audio HAL for SC7727
+Version: 0.1.0
+Release: 0
+Group: System/Libraries
+License: Apache-2.0
+URL: http://tizen.org
+Source0: audio-hal-sc7727-%{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 SC7727
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+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}
+mkdir -p %{buildroot}%{_datadir}/license
+cp LICENSE.Apache-2.0 %{buildroot}%{_datadir}/license/%{name}
+%make_install
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest audio-hal-sc7727.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libtizen-audio.so
+%{_datadir}/license/%{name}
diff --git a/tizen-audio-device.c b/tizen-audio-device.c
new file mode 100644
index 0000000..799dbb4
--- /dev/null
+++ b/tizen-audio-device.c
@@ -0,0 +1,1037 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 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"
+
+/* #define DEBUG_TIMING */
+
+static device_type_t outDeviceTypes[] = {
+ { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
+ { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
+ { AUDIO_DEVICE_OUT_JACK, "Headphones" },
+ { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
+ { AUDIO_DEVICE_OUT_AUX, "Line" },
+ { AUDIO_DEVICE_OUT_HDMI, "HDMI" },
+ { 0, 0 },
+};
+
+static device_type_t inDeviceTypes[] = {
+ { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
+ { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
+ { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
+ { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
+ { 0, 0 },
+};
+
+static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t direction)
+{
+ uint32_t device = 0;
+
+ if (!strncmp(device_str,"builtin-speaker", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (!strncmp(device_str,"builtin-receiver", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_RECEIVER;
+ } else if ((!strncmp(device_str,"audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_JACK;
+ } else if ((!strncmp(device_str,"bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_BT_SCO;
+ } else if (!strncmp(device_str,"aux", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_AUX;
+ } else if (!strncmp(device_str,"hdmi", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_HDMI;
+ } else if ((!strncmp(device_str,"builtin-mic", MAX_NAME_LEN))) {
+ device = AUDIO_DEVICE_IN_MAIN_MIC;
+ /* To Do : SUB_MIC */
+ } else if ((!strncmp(device_str,"audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_JACK;
+ } else if ((!strncmp(device_str,"bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_BT_SCO;
+ } else {
+ device = AUDIO_DEVICE_NONE;
+ }
+ AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
+ return device;
+}
+
+static audio_return_t set_devices(audio_mgr_t *am, 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;
+
+ 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) && am->device.active_in) {
+ /* check the active in devices */
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (((am->device.active_in & (~0x80000000)) & inDeviceTypes[j].type))
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ }
+ } else if ((devices[0].direction == AUDIO_DIRECTION_IN) && am->device.active_out) {
+ /* check the active out devices */
+ for (j = 0; j < outDeviceTypes[j].type; j++) {
+ if (am->device.active_out & outDeviceTypes[j].type)
+ active_devices[dev_idx++] = outDeviceTypes[j].name;
+ }
+ }
+
+ for (i = 0; i < num_of_devices; i++) {
+ new_device = convert_device_string_to_enum(devices[i].type, devices[i].direction);
+ if (new_device & 0x80000000) {
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (new_device == inDeviceTypes[j].type) {
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ am->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;
+ am->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 = _audio_ucm_set_devices(am, verb, active_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
+ return audio_ret;
+ }
+ return audio_ret;
+
+}
+
+audio_return_t _audio_device_init (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ am->device.active_in = 0x0;
+ am->device.active_out = 0x0;
+ am->device.pcm_in = NULL;
+ am->device.pcm_out = NULL;
+ am->device.mode = VERB_NORMAL;
+ pthread_mutex_init(&am->device.pcm_lock, NULL);
+ am->device.pcm_count = 0;
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_device_deinit (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+static audio_return_t _do_route_ap_playback_capture (audio_mgr_t *am, audio_route_info_t *route_info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ device_info_t *devices = route_info->device_infos;
+ const char *verb = NULL;
+
+ /* To Do: Set modifiers */
+ /* int mod_idx = 0; */
+ /* const char *modifiers[MAX_MODIFIERS] = {NULL,}; */
+
+ verb = AUDIO_USE_CASE_VERB_HIFI;
+ AUDIO_LOG_INFO("do_route_ap_playback_capture++ ");
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ audio_ret = set_devices(am, 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;
+ }
+ am->device.mode = VERB_NORMAL;
+
+ /* To Do: Set modifiers */
+ /*
+ if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
+ } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
+ if (am->device.active_out &= AUDIO_DEVICE_OUT_JACK)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
+ else
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
+ } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
+ if (am->device.active_out &= AUDIO_DEVICE_OUT_JACK)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_RINGTONE;
+ else
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
+ } else {
+ if (am->device.active_in)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
+ else
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
+ }
+ audio_ret = _audio_ucm_set_modifiers (am, verb, modifiers);
+ */
+
+ return audio_ret;
+}
+audio_return_t _do_route_voicecall (audio_mgr_t *am, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = NULL;
+ verb = AUDIO_USE_CASE_VERB_VOICECALL;
+
+ AUDIO_LOG_INFO("do_route_voicecall++");
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ audio_ret = set_devices(am, verb, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ /* FIXME. Get network info and configure rate in pcm device */
+ am->device.mode = VERB_CALL;
+ if (am->device.active_out && am->device.active_in)
+ _voice_pcm_open(am);
+
+ return audio_ret;
+}
+audio_return_t _do_route_voip (audio_mgr_t *am, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = NULL;
+ const char *active_devices[MAX_DEVICES] = {NULL,};
+ verb = AUDIO_USE_CASE_VERB_HIFI;
+
+ AUDIO_LOG_INFO("do_route_voip++");
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ audio_ret = set_devices(am, verb, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ /* FIXME. If necessary, set VERB_VOIP */
+ am->device.mode = VERB_NORMAL;
+ if (active_devices == NULL) {
+ AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ /* TO DO: Set modifiers */
+ return audio_ret;
+}
+
+audio_return_t _do_route_reset (audio_mgr_t *am, uint32_t direction)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ /* FIXME: If you need to reset, set verb inactive */
+ /* const char *verb = NULL; */
+ /* verb = AUDIO_USE_CASE_VERB_INACTIVE; */
+
+ AUDIO_LOG_INFO("do_route_reset++, direction(%p)", direction);
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ if (direction == AUDIO_DIRECTION_OUT) {
+ am->device.active_out &= 0x0;
+ } else {
+ am->device.active_in &= 0x0;
+ }
+ if (am->device.mode == VERB_CALL) {
+ _voice_pcm_close(am, direction);
+ }
+ /* TO DO: Set Inactive */
+ return audio_ret;
+}
+
+audio_return_t audio_do_route (void *userdata, audio_route_info_t *info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ device_info_t *devices = info->device_infos;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s", info->role);
+
+ if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
+ audio_ret = _do_route_voicecall(am, devices, info->num_of_devices);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+ }
+ } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
+ audio_ret = _do_route_voip(am, devices, info->num_of_devices);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set voip route return 0x%x", audio_ret);
+ }
+ } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
+ audio_ret = _do_route_reset(am, devices->direction);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set reset return 0x%x", audio_ret);
+ }
+ } else {
+ /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
+ audio_ret = _do_route_ap_playback_capture(am, info);
+
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
+ }
+ }
+ return audio_ret;
+}
+
+audio_return_t audio_update_stream_connection_info (void *userdata, audio_stream_info_t *info, uint32_t is_connected)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, 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;
+}
+
+audio_return_t audio_update_route_option (void *userdata, audio_route_option_t *option)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
+
+ return audio_ret;
+}
+
+static int __voice_pcm_set_params (audio_mgr_t *am, snd_pcm_t *pcm)
+{
+ snd_pcm_hw_params_t *params = NULL;
+ int err = 0;
+ unsigned int val = 0;
+
+ /* 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, 16000, 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, 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;
+}
+
+int _voice_pcm_open (audio_mgr_t *am)
+{
+ int err, ret = 0;
+ AUDIO_LOG_INFO("open voice pcm handles");
+
+ /* Get playback voice-pcm from ucm conf. Open and set-params */
+ if ((err = snd_pcm_open((void **)&am->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(am, am->device.pcm_out);
+
+ AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
+
+ /* Get capture voice-pcm from ucm conf. Open and set-params */
+ if ((err = snd_pcm_open((void **)&am->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(am, am->device.pcm_in);
+ AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
+
+ return ret;
+}
+
+int _voice_pcm_close (audio_mgr_t *am, uint32_t direction)
+{
+ AUDIO_LOG_INFO("close voice pcm handles");
+
+ if (am->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
+ audio_pcm_close((void *)am, am->device.pcm_out);
+ am->device.pcm_out = NULL;
+ AUDIO_LOG_INFO("voice pcm_out handle close success");
+ } else if (am->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
+ audio_pcm_close((void *)am, am->device.pcm_in);
+ am->device.pcm_in = NULL;
+ AUDIO_LOG_INFO("voice pcm_in handle close success");
+ }
+
+ return 0;
+}
+
+#ifdef __USE_TINYALSA__
+static struct pcm *__tinyalsa_open_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;
+
+ 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("direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d", direction, ss->channels, ss->rate, ss->format, period_size, period_count);
+
+ pcm = pcm_open((direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_CARD_ID : CAPTURE_CARD_ID,
+ (direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_PCM_DEVICE_ID : CAPTURE_PCM_DEVICE_ID,
+ (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;
+}
+#endif
+
+audio_return_t audio_pcm_open (void *userdata, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+#ifdef __USE_TINYALSA__
+ audio_mgr_t *am;
+ audio_pcm_sample_spec_t *ss;
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(userdata, 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);
+
+ am = (audio_mgr_t *)userdata;
+ ss = (audio_pcm_sample_spec_t *)sample_spec;
+ ss->format = _convert_format((audio_sample_format_t)ss->format);
+
+ *pcm_handle = __tinyalsa_open_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);
+ }
+
+ am->device.pcm_count++;
+ AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
+#else /* alsa-lib */
+ audio_mgr_t *am;
+ int err, mode;
+ char *device_name = NULL;
+ uint8_t use_mmap = 0;
+ snd_pcm_uframes_t buffer_size;
+
+ AUDIO_RETURN_VAL_IF_FAIL(userdata, 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);
+
+ am = (audio_mgr_t *)userdata;
+ mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
+ buffer_size = (snd_pcm_uframes_t)(period_size * periods);
+
+ if(direction == AUDIO_DIRECTION_OUT)
+ device_name = PLAYBACK_PCM_DEVICE;
+ else if (direction == AUDIO_DIRECTION_IN)
+ device_name = CAPTURE_PCM_DEVICE;
+ else {
+ AUDIO_LOG_ERROR("Error get device_name, direction : %d", direction);
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ 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 ((err = audio_pcm_set_params(userdata, *pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", err);
+ return err;
+ }
+
+ am->device.pcm_count++;
+ AUDIO_LOG_INFO("Opening PCM handle 0x%x, PCM device %s", *pcm_handle, device_name);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_start (void *userdata, 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 0x%x start", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_stop (void *userdata, 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 0x%x stop", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_close (void *userdata, void *pcm_handle)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ int err;
+
+ AUDIO_LOG_INFO("Try to close PCM handle 0x%x", 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
+
+ pcm_handle = NULL;
+ am->device.pcm_count--;
+ AUDIO_LOG_INFO("PCM handle close success (count:%d)", am->device.pcm_count);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_avail (void *userdata, void *pcm_handle, uint32_t *avail)
+{
+#ifdef __USE_TINYALSA__
+ struct timespec tspec;
+ unsigned int frames_avail = 0;
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
+
+ err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle 0x%x : %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;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
+
+ if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not get avail at PCM handle 0x%x : %d", 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 audio_pcm_write (void *userdata, void *pcm_handle, const void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ 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("audio_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 : %d", frames_written);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("audio_pcm_write = (%d / %d)", frames_written, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_read (void *userdata, void *pcm_handle, void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ 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;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
+ if (frames_read < 0) {
+ AUDIO_LOG_ERROR("Failed to read pcm : %d", frames_read);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("audio_pcm_read = (%d / %d)", frames_read, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_get_fd(void *userdata, void *pcm_handle, int *fd)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
+#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;
+}
+
+#ifdef __USE_TINYALSA__
+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
+
+audio_return_t audio_pcm_recover(void *userdata, 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("audio_pcm_recover");
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_get_params(void *userdata, 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;
+
+ 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);
+ ss = (audio_pcm_sample_spec_t *)*sample_spec;
+
+ _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("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", 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;
+
+ 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);
+ 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 : %s", 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 : %s", err);
+ }
+
+ AUDIO_LOG_DEBUG("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_set_params(void *userdata, 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("audio_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;
+
+ 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);
+ 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, NULL)) < 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", 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", 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(%u) failed : %d", periods * periods, 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("audio_pcm_set_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, ss.format, ss.rate, ss.channels, period_size, periods, _buffer_size);
+#endif
+
+ return AUDIO_RET_OK;
+}
diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h
new file mode 100644
index 0000000..4bf51ec
--- /dev/null
+++ b/tizen-audio-internal.h
@@ -0,0 +1,247 @@
+#ifndef footizenaudiointernalfoo
+#define footizenaudiointernalfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dlog.h>
+#include <time.h>
+#include <sys/types.h>
+#include <asoundlib.h>
+#ifdef __USE_TINYALSA__
+#include <tinyalsa/asoundlib.h>
+#endif
+#include <pthread.h>
+#include <use-case.h>
+#include "tizen-audio.h"
+
+/* Debug */
+
+//#define AUDIO_DEBUG
+#define PROPERTY_VALUE_MAX 92
+#define BUF_SIZE 1024
+#define AUDIO_DUMP_STR_LEN 256
+#define AUDIO_DEVICE_INFO_LIST_MAX 16
+#ifdef USE_DLOG
+#ifdef DLOG_TAG
+#undef DLOG_TAG
+#endif
+#define DLOG_TAG "AUDIO_HAL"
+#define AUDIO_LOG_ERROR(...) SLOG(LOG_ERROR, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_WARN(...) SLOG(LOG_WARN, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_INFO(...) SLOG(LOG_INFO, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_DEBUG(...) SLOG(LOG_DEBUG, DLOG_TAG, __VA_ARGS__)
+#define AUDIO_LOG_VERBOSE(...) SLOG(LOG_DEBUG, DLOG_TAG, __VA_ARGS__)
+#else
+#define AUDIO_LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
+#define AUDIO_LOG_WARN(...) fprintf(stderr, __VA_ARGS__)
+#define AUDIO_LOG_INFO(...) fprintf(stdout, __VA_ARGS__)
+#define AUDIO_LOG_DEBUG(...) fprintf(stdout, __VA_ARGS__)
+#define AUDIO_LOG_VERBOSE(...) fprintf(stdout, __VA_ARGS__)
+#endif
+
+#define AUDIO_RETURN_IF_FAIL(expr) do { \
+ if (!expr) { \
+ AUDIO_LOG_ERROR("%s failed", #expr); \
+ return; \
+ } \
+} while (0)
+#define AUDIO_RETURN_VAL_IF_FAIL(expr, val) do { \
+ if (!expr) { \
+ AUDIO_LOG_ERROR("%s failed", #expr); \
+ return val; \
+ } \
+} while (0)
+
+/* Devices : Normal */
+enum audio_device_type {
+ AUDIO_DEVICE_NONE = 0,
+
+ /* output devices */
+ AUDIO_DEVICE_OUT_SPEAKER = 0x00000001,
+ AUDIO_DEVICE_OUT_RECEIVER = 0x00000002,
+ AUDIO_DEVICE_OUT_JACK = 0x00000004,
+ AUDIO_DEVICE_OUT_BT_SCO = 0x00000008,
+ AUDIO_DEVICE_OUT_AUX = 0x00000010,
+ AUDIO_DEVICE_OUT_HDMI = 0x00000020,
+ AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_RECEIVER |
+ AUDIO_DEVICE_OUT_JACK |
+ AUDIO_DEVICE_OUT_BT_SCO |
+ AUDIO_DEVICE_OUT_AUX |
+ AUDIO_DEVICE_OUT_HDMI),
+ /* input devices */
+ AUDIO_DEVICE_IN_MAIN_MIC = 0x80000001,
+ AUDIO_DEVICE_IN_SUB_MIC = 0x80000002,
+ AUDIO_DEVICE_IN_JACK = 0x80000004,
+ AUDIO_DEVICE_IN_BT_SCO = 0x80000008,
+ AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_MAIN_MIC |
+ AUDIO_DEVICE_IN_SUB_MIC |
+ AUDIO_DEVICE_IN_JACK |
+ AUDIO_DEVICE_IN_BT_SCO),
+};
+
+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 "VoiceCall"
+#define AUDIO_USE_CASE_VERB_LOOPBACK "Loopback"
+#define AUDIO_USE_CASE_VERB_FMRADIO "FM_Radio"
+
+/* Modifiers */
+#define AUDIO_USE_CASE_MODIFIER_VOICESEARCH "VoiceSearch"
+#define AUDIO_USE_CASE_MODIFIER_CAMCORDING "Camcording"
+#define AUDIO_USE_CASE_MODIFIER_RINGTONE "Ringtone"
+#define AUDIO_USE_CASE_MODIFIER_DUAL_RINGTONE "DualRingtone"
+#define AUDIO_USE_CASE_MODIFIER_MEDIA "Media"
+#define AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA "DualMedia"
+
+#define streq !strcmp
+#define strneq strcmp
+
+#define ALSA_DEFAULT_CARD "sprdphone"
+#define VOICE_PCM_DEVICE "hw:0,1"
+#define PLAYBACK_PCM_DEVICE "hw:sprdphone,0"
+#define CAPTURE_PCM_DEVICE "hw:sprdphone,0"
+
+#define PLAYBACK_CARD_ID ALSA_DEFAULT_CARD
+#define PLAYBACK_PCM_DEVICE_ID 0
+
+#define CAPTURE_CARD_ID ALSA_DEFAULT_CARD
+#define CAPTURE_PCM_DEVICE_ID 0
+
+#define MAX_DEVICES 5
+#define MAX_MODIFIERS 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;
+
+/* Device */
+typedef enum audio_route_mode{
+ VERB_NORMAL,
+ VERB_CALL,
+ VERB_VOIP
+} audio_route_mode_t;
+
+typedef struct audio_device_mgr {
+ uint32_t active_in;
+ uint32_t active_out;
+ snd_pcm_t *pcm_in;
+ snd_pcm_t *pcm_out;
+ pthread_mutex_t pcm_lock;
+ uint32_t pcm_count;
+ audio_route_mode_t mode;
+} audio_device_mgr_t;
+
+
+/* Stream */
+
+#define AUDIO_VOLUME_LEVEL_MAX 16
+
+typedef struct audio_volume_value_table {
+ double volume[AUDIO_VOLUME_TYPE_MAX][AUDIO_VOLUME_LEVEL_MAX];
+ uint32_t volume_level_max[AUDIO_VOLUME_LEVEL_MAX];
+ double gain[AUDIO_GAIN_TYPE_MAX];
+} audio_volume_value_table_t;
+
+enum {
+ AUDIO_VOLUME_DEVICE_DEFAULT,
+ AUDIO_VOLUME_DEVICE_MAX,
+};
+
+typedef struct audio_volume_mgr {
+ uint32_t volume_level[AUDIO_VOLUME_TYPE_MAX];
+ audio_volume_value_table_t *volume_value_table;
+} audio_volume_mgr_t;
+
+typedef struct audio_ucm_mgr {
+ snd_use_case_mgr_t* uc_mgr;
+} audio_ucm_mgr_t;
+
+typedef struct audio_mixer_mgr {
+ 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_mixer_mgr_t;
+
+/* Overall */
+
+typedef struct audio_mgr {
+ audio_device_mgr_t device;
+ audio_volume_mgr_t volume;
+ audio_ucm_mgr_t ucm;
+ audio_mixer_mgr_t mixer;
+} audio_mgr_t;
+
+typedef struct {
+ unsigned short is_open; /* if is_open is true, open device; else close device.*/
+ unsigned short is_headphone;
+ unsigned int is_downlink_mute;
+ unsigned int is_uplink_mute;
+} device_ctrl_t;
+
+typedef struct samplerate_ctrl {
+ unsigned int samplerate; /* change samplerate.*/
+} set_samplerate_t;
+
+audio_return_t _audio_volume_init (audio_mgr_t *am);
+audio_return_t _audio_volume_deinit (audio_mgr_t *am);
+
+audio_return_t _audio_device_init (audio_mgr_t *am);
+audio_return_t _audio_device_deinit (audio_mgr_t * am);
+audio_return_t _audio_ucm_init (audio_mgr_t *am);
+audio_return_t _audio_ucm_deinit (audio_mgr_t *am);
+void _audio_ucm_get_device_name (audio_mgr_t *am, const char *use_case, audio_direction_t direction, const char **value);
+#define _audio_ucm_update_use_case _audio_ucm_set_use_case
+audio_return_t _audio_ucm_set_use_case (audio_mgr_t *am, const char *verb, const char *devices[], const char *modifiers[]);
+audio_return_t _audio_ucm_set_devices (audio_mgr_t *am, const char *verb, const char *devices[]);
+audio_return_t _audio_ucm_set_modifiers (audio_mgr_t *am, const char *verb, const char *modifiers[]);
+int _audio_ucm_fill_device_info_list (audio_mgr_t *am, audio_device_info_t *device_info_list, const char *verb);
+int _voice_pcm_open(audio_mgr_t *am);
+int _voice_pcm_close(audio_mgr_t *am, uint32_t direction);
+audio_return_t _audio_ucm_get_verb (audio_mgr_t *am, const char **value);
+audio_return_t _audio_ucm_reset_use_case (audio_mgr_t *am);
+audio_return_t _audio_util_init (audio_mgr_t *am);
+audio_return_t _audio_util_deinit (audio_mgr_t *am);
+audio_return_t _audio_mixer_control_set_param(audio_mgr_t *am, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
+audio_return_t _audio_mixer_control_set_value(audio_mgr_t *am, const char *ctl_name, int val);
+audio_return_t _audio_mixer_control_set_value_string(audio_mgr_t *am, const char* ctl_name, const char* value);
+audio_return_t _audio_mixer_control_get_value(audio_mgr_t *am, const char *ctl_name, int *val);
+audio_return_t _audio_mixer_control_get_element(audio_mgr_t *am, const char *ctl_name, snd_hctl_elem_t **elem);
+audio_return_t _audio_pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event);
+audio_return_t _audio_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);
+uint32_t _convert_format(audio_sample_format_t format);
+#endif
diff --git a/tizen-audio-ucm.c b/tizen-audio-ucm.c
new file mode 100644
index 0000000..ba8cc5e
--- /dev/null
+++ b/tizen-audio-ucm.c
@@ -0,0 +1,718 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 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
+
+audio_return_t _audio_ucm_init (audio_mgr_t *am)
+{
+ snd_use_case_mgr_open(&am->ucm.uc_mgr, ALSA_DEFAULT_CARD);
+
+ if (!am->ucm.uc_mgr) {
+ AUDIO_LOG_ERROR("uc_mgr open failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_ucm_deinit (audio_mgr_t *am)
+{
+ if (am->ucm.uc_mgr != NULL) {
+ snd_use_case_mgr_close(am->ucm.uc_mgr);
+ am->ucm.uc_mgr = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+void _audio_ucm_get_device_name (audio_mgr_t *am, const char *use_case, audio_direction_t direction, const char **value)
+{
+ char identifier[70] = {0};
+
+ if (direction == AUDIO_DIRECTION_IN) {
+ sprintf(identifier, "CapturePCM//%s", use_case);
+ } else {
+ sprintf(identifier, "PlaybackPCM//%s", use_case);
+ }
+ snd_use_case_get(am->ucm.uc_mgr, identifier, value);
+}
+
+static inline void __add_ucm_device_info (audio_mgr_t *am, const char *use_case, audio_direction_t direction, audio_device_info_t *device_info_list, int *device_info_count)
+{
+ audio_device_info_t *device_info;
+ const char *device_name = NULL;
+ char *needle = NULL;
+
+ _audio_ucm_get_device_name(am, use_case, direction, &device_name);
+ if (device_name) {
+ device_info = &device_info_list[(*device_info_count)++];
+
+ memset(device_info, 0x00, sizeof(audio_device_info_t));
+ device_info->api = AUDIO_DEVICE_API_ALSA;
+ device_info->direction = direction;
+ needle = strstr(&device_name[3], ",");
+ if (needle) {
+ device_info->alsa.device_idx = *(needle+1) - '0';
+ device_info->alsa.card_name = strndup(&device_name[3], needle - (device_name+3));
+ device_info->alsa.card_idx = snd_card_get_index(device_info->alsa.card_name);
+ AUDIO_LOG_DEBUG("Card name: %s", device_info->alsa.card_name);
+ }
+
+ free((void *)device_name);
+ }
+}
+
+int _audio_ucm_fill_device_info_list (audio_mgr_t *am, audio_device_info_t *device_info_list, const char *verb)
+{
+ int device_info_count = 0;
+ const char *curr_verb = NULL;
+
+ if (!verb) {
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &curr_verb);
+ verb = curr_verb;
+ }
+
+ /* prepare destination */
+ /*If the devices are VOICECALL LOOPBACK or FMRADIO then pulseaudio need not get the device notification*/
+ if (verb) {
+ if (strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, strlen(AUDIO_USE_CASE_VERB_VOICECALL)) &&
+ strncmp(verb, AUDIO_USE_CASE_VERB_LOOPBACK, strlen(AUDIO_USE_CASE_VERB_LOOPBACK))) {
+ __add_ucm_device_info(am, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
+ if(strncmp(verb, AUDIO_USE_CASE_VERB_FMRADIO, strlen(AUDIO_USE_CASE_VERB_FMRADIO))) {
+ __add_ucm_device_info(am, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
+ }
+ }
+
+ if (curr_verb)
+ free((void *)curr_verb);
+
+ }
+
+ return device_info_count;
+}
+
+static void __dump_use_case(const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count, char *dump)
+{
+ int i, len;
+
+ len = sprintf(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
+ if (len > 0)
+ dump += len;
+
+ for (i = 0; i < dev_count; i++) {
+ if (i != dev_count - 1) {
+ len = sprintf(dump, "%s, ", devices[i]);
+ } else {
+ len = sprintf(dump, "%s", devices[i]);
+ }
+ if (len > 0)
+ dump += len;
+ }
+
+ len = sprintf(dump, " ] Modifier [ ");
+ if (len > 0)
+ dump += len;
+
+ for (i = 0; i < mod_count; i++) {
+ if (i != mod_count - 1) {
+ len = sprintf(dump, "%s, ", modifiers[i]);
+ } else {
+ len = sprintf(dump, "%s", modifiers[i]);
+ }
+ if (len > 0)
+ dump += len;
+ }
+
+ len = sprintf(dump, " ]");
+ if (len > 0)
+ dump += len;
+
+ *dump = '\0';
+}
+
+#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
+
+/* 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 _audio_ucm_set_use_case (audio_mgr_t *am, 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;
+ char dump_str[512];
+
+ if (!am->ucm.uc_mgr || !verb)
+ return AUDIO_ERR_PARAMETER;
+
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
+ old_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &old_dev_list);
+ old_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &old_mod_list);
+ __dump_use_case(old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
+
+ 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(verb, devices, dev_count, modifiers, mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("> UCM requested %s", dump_str);
+
+ 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(am->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(am->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(am->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(am->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(am->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(am->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(am->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(am->ucm.uc_mgr, "_verb", &new_verb);
+ new_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &new_dev_list);
+ new_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &new_mod_list);
+ __dump_use_case(new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
+
+ 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 _audio_ucm_set_devices (audio_mgr_t *am, 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;
+ char dump_str[512];
+
+ if (!am->ucm.uc_mgr || !verb)
+ return AUDIO_ERR_PARAMETER;
+
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
+ old_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &old_dev_list);
+ __dump_use_case(old_verb, old_dev_list, old_dev_count, NULL, 0, &dump_str[0]);
+ AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
+
+ if (devices) {
+ for (dev_count = 0; devices[dev_count]; dev_count++);
+ }
+
+ __dump_use_case(verb, devices, dev_count, NULL, 0, &dump_str[0]);
+ AUDIO_LOG_INFO("> UCM requested %s", dump_str);
+
+ 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(am->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(am->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_DEBUG("Setting new verb: %s", verb);
+ /* set new verb */
+ if (snd_use_case_set(am->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(am->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(am->ucm.uc_mgr, "_verb", &new_verb);
+ new_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &new_dev_list);
+ __dump_use_case(new_verb, new_dev_list, new_dev_count, NULL, 0, &dump_str[0]);
+ AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
+
+ 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 _audio_ucm_set_modifiers (audio_mgr_t *am, 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;
+ char dump_str[512];
+
+ if (!am->ucm.uc_mgr || !verb)
+ return AUDIO_ERR_PARAMETER;
+
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
+ old_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &old_mod_list);
+ __dump_use_case(old_verb, NULL, 0, old_mod_list, old_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
+
+ if (modifiers) {
+ for (mod_count = 0; modifiers[mod_count]; mod_count++);
+ }
+
+ __dump_use_case(verb, NULL, 0, modifiers, mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("> UCM requested %s", dump_str);
+
+ 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(am->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(am->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(am->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(am->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(am->ucm.uc_mgr, "_verb", &new_verb);
+ new_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &new_mod_list);
+ __dump_use_case(new_verb, NULL, 0, new_mod_list, new_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
+
+ 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 _audio_ucm_get_verb (audio_mgr_t *am, const char **value)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
+
+ if ((ret = snd_use_case_get(am->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 _audio_ucm_reset_use_case (audio_mgr_t *am)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
+
+ if ((ret = snd_use_case_set(am->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-util.c b/tizen-audio-util.c
new file mode 100644
index 0000000..83785c0
--- /dev/null
+++ b/tizen-audio-util.c
@@ -0,0 +1,427 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 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"
+
+audio_return_t _audio_util_init (audio_mgr_t *am)
+{
+ pthread_mutex_init(&(am->mixer.mutex), NULL);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_util_deinit (audio_mgr_t *am)
+{
+ pthread_mutex_destroy(&(am->mixer.mutex));
+ return AUDIO_RET_OK;
+}
+
+#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 _audio_mixer_control_set_param(audio_mgr_t *am, const char* ctl_name, snd_ctl_elem_value_t* param, int size)
+{
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_mixer_control_get_value (void *userdata, const char *ctl_name, int *val)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_ret = _audio_mixer_control_get_value(am, ctl_name, val);
+ return audio_ret;
+}
+
+audio_return_t _audio_mixer_control_get_value(audio_mgr_t *am, 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;
+
+ pthread_mutex_lock(&(am->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(&(am->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(&(am->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR ("Error\n");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(am->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_t _audio_mixer_control_set_value(audio_mgr_t *am, 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;
+
+ char *card_name = NULL;
+ int ret = 0, count = 0, i = 0;
+
+ pthread_mutex_lock(&(am->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", card_name, snd_strerror(ret));
+ pthread_mutex_unlock(&(am->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(&(am->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR("Error");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(am->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_t _audio_mixer_control_set_value_string(audio_mgr_t *am, const char* ctl_name, const char* value)
+{
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+
+audio_return_t _audio_mixer_control_get_element(audio_mgr_t *am, const char *ctl_name, snd_hctl_elem_t **elem)
+{
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+#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 */
+/* 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
+
+uint32_t _convert_format(audio_sample_format_t format)
+{
+ return g_format_convert_table[format];
+}
+
+/* Generic snd pcm interface APIs */
+audio_return_t _audio_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;
+
+ 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 _audio_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;
+
+ 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-volume.c b/tizen-audio-volume.c
new file mode 100644
index 0000000..e841f4a
--- /dev/null
+++ b/tizen-audio-volume.c
@@ -0,0 +1,398 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 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 "/usr/etc/mmfw_audio_volume.ini"
+#define VOLUME_INI_TEMP_PATH "/opt/system/mmfw_audio_volume.ini"
+#define VOLUME_VALUE_MAX (1.0f)
+#define GAIN_VALUE_MAX (1.0f)
+
+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 */
+ "file/private/sound/volume/fixed", /* AUDIO_VOLUME_TYPE_FIXED */
+};
+
+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";
+ case AUDIO_VOLUME_TYPE_FIXED: return "fixed";
+ 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 if (!strncmp(vol_type, "fixed", strlen(vol_type)) || !strncmp(vol_type, "8", strlen(vol_type)))
+ return AUDIO_VOLUME_TYPE_FIXED;
+ 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_mgr_t *am)
+{
+ audio_volume_value_table_t *volume_value_table = am->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 < volume_value_table->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 = am->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_mgr_t *am)
+{
+ dictionary * dict = NULL;
+ uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
+ audio_volume_value_table_t *volume_value_table = am->volume.volume_value_table;
+ int size = 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);
+
+ volume_value_table->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][volume_value_table->volume_level_max[vol_type_idx]++] = vol_value;
+ token = strtok_r(NULL, delimiter, &ptr);
+ }
+ } else {
+ volume_value_table->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(am);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_volume_init (audio_mgr_t *am)
+{
+ 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, 4, 0 };
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
+ am->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);
+ am->volume.volume_level[i] = val;
+ }
+
+ if (!(am->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(am);
+ 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_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ if (am->volume.volume_value_table) {
+ free(am->volume.volume_value_table);
+ am->volume.volume_value_table = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_get_volume_level_max (void *userdata, audio_volume_info_t *info, uint32_t *level)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_value_table_t *volume_value_table;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(am->volume.volume_value_table, AUDIO_ERR_PARAMETER);
+
+ /* Get max volume level by device & type */
+ volume_value_table = am->volume.volume_value_table;
+ *level = volume_value_table->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 *userdata, audio_volume_info_t *info, uint32_t *level)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ *level = am->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 *userdata, audio_volume_info_t *info, uint32_t level, double *value)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_value_table_t *volume_value_table;
+ char dump_str[AUDIO_DUMP_STR_LEN] = {0,};
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(am->volume.volume_value_table, AUDIO_ERR_PARAMETER);
+
+ /* Get basic volume by device & type & level */
+ volume_value_table = am->volume.volume_value_table;
+ if (volume_value_table->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 *userdata, audio_volume_info_t *info, uint32_t level)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ /* Update volume level */
+ am->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 *userdata, audio_volume_info_t *info, uint32_t *mute)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ /* TODO. Not implemented */
+
+ return audio_ret;
+}
+
+audio_return_t audio_set_volume_mute (void *userdata, audio_volume_info_t *info, uint32_t mute)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, 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..b7df609
--- /dev/null
+++ b/tizen-audio.c
@@ -0,0 +1,263 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 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 **userdata)
+{
+ audio_mgr_t *am;
+ audio_return_t ret = AUDIO_RET_OK;
+
+ if (!(am = malloc(sizeof(audio_mgr_t)))) {
+ AUDIO_LOG_ERROR("am malloc failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_device_init(am)))) {
+ AUDIO_LOG_ERROR("device init failed");
+ goto error_exit;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_volume_init(am)))) {
+ AUDIO_LOG_ERROR("stream init failed");
+ goto error_exit;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_ucm_init(am)))) {
+ AUDIO_LOG_ERROR("ucm init failed");
+ goto error_exit;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_util_init(am)))) {
+ AUDIO_LOG_ERROR("mixer init failed");
+ goto error_exit;
+ }
+
+ *userdata = (void *)am;
+ return AUDIO_RET_OK;
+
+error_exit:
+ if (am)
+ free(am);
+
+ return ret;
+}
+
+audio_return_t audio_deinit (void **userdata)
+{
+ audio_mgr_t *am = (audio_mgr_t *)*userdata;
+
+ if (am) {
+ _audio_device_deinit(am);
+ _audio_volume_deinit(am);
+ _audio_ucm_deinit(am);
+ _audio_util_deinit(am);
+ free(am);
+ *userdata = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+static const unsigned int SAMPLES_PER_PERIOD_DEFAULT = 1536; /* Frames */
+static const unsigned int PERIODS_PER_BUFFER_FASTMODE = 4;
+static const unsigned int PERIODS_PER_BUFFER_DEFAULT = 6;
+static const unsigned int PERIODS_PER_BUFFER_VOIP = 2;
+static const unsigned int PERIODS_PER_BUFFER_PLAYBACK = 8;
+static const unsigned int PERIODS_PER_BUFFER_CAPTURE = 12;
+static const unsigned int PERIODS_PER_BUFFER_VIDEO = 10;
+
+
+/* Latency msec */
+static const unsigned int PERIOD_TIME_FOR_ULOW_LATENCY_MSEC = 20;
+static const unsigned int PERIOD_TIME_FOR_LOW_LATENCY_MSEC = 25;
+static const unsigned int PERIOD_TIME_FOR_MID_LATENCY_MSEC = 50;
+static const unsigned int PERIOD_TIME_FOR_HIGH_LATENCY_MSEC = 75;
+static const unsigned int PERIOD_TIME_FOR_UHIGH_LATENCY_MSEC = 150;
+static const unsigned int PERIOD_TIME_FOR_VOIP_LATENCY_MSEC = 20;
+
+static const uint32_t g_size_table[] = {
+ [AUDIO_SAMPLE_U8] = 1,
+ [AUDIO_SAMPLE_ULAW] = 1,
+ [AUDIO_SAMPLE_ALAW] = 1,
+ [AUDIO_SAMPLE_S16LE] = 2,
+ [AUDIO_SAMPLE_S16BE] = 2,
+ [AUDIO_SAMPLE_FLOAT32LE] = 4,
+ [AUDIO_SAMPLE_FLOAT32BE] = 4,
+ [AUDIO_SAMPLE_S32LE] = 4,
+ [AUDIO_SAMPLE_S32BE] = 4,
+ [AUDIO_SAMPLE_S24LE] = 3,
+ [AUDIO_SAMPLE_S24BE] = 3,
+ [AUDIO_SAMPLE_S24_32LE] = 4,
+ [AUDIO_SAMPLE_S24_32BE] = 4
+};
+
+int _sample_spec_valid(uint32_t rate, audio_sample_format_t format, uint32_t channels)
+{
+ if ((rate <= 0 ||
+ rate > (48000U*4U) ||
+ channels <= 0 ||
+ channels > 32U ||
+ format >= AUDIO_SAMPLE_MAX ||
+ format < AUDIO_SAMPLE_U8))
+ return 0;
+
+ AUDIO_LOG_ERROR("hal-latency - _sample_spec_valid() -> return true");
+
+ return 1;
+}
+
+uint32_t _audio_usec_to_bytes(uint64_t t, uint32_t rate, audio_sample_format_t format, uint32_t channels)
+{
+ uint32_t ret = (uint32_t) (((t * rate) / 1000000ULL)) * (g_size_table[format] * channels);
+ AUDIO_LOG_DEBUG("hal-latency - return %d", ret);
+ return ret;
+}
+
+uint32_t _audio_sample_size(audio_sample_format_t format)
+{
+ return g_size_table[format];
+}
+audio_return_t audio_get_buffer_attr(void *userdata,
+ uint32_t direction,
+ const char *latency,
+ uint32_t samplerate,
+ audio_sample_format_t format,
+ uint32_t channels,
+ uint32_t *maxlength,
+ uint32_t *tlength,
+ uint32_t *prebuf,
+ uint32_t *minreq,
+ uint32_t *fragsize)
+{
+ assert(userdata);
+ assert(latency);
+ assert(maxlength);
+ assert(tlength);
+ assert(prebuf);
+ assert(minreq);
+ assert(fragsize);
+
+ AUDIO_LOG_DEBUG("hal-latency - audio_get_buffer_attr(direction:%d, latency:%s, samplerate:%d, format:%d, channels:%d)", direction, latency, samplerate, format, channels);
+
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ uint32_t period_time = 0,
+ sample_per_period = 0,
+ periods_per_buffer = 0;
+
+ if (_sample_spec_valid(samplerate, format, channels) == 0) {
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if (direction == AUDIO_DIRECTION_IN) {
+ if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_LOW");
+ period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_FASTMODE;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * _audio_sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_MID");
+ period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_DEFAULT;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * _audio_sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_HIGH");
+ period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_CAPTURE;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * _audio_sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_VOIP");
+ period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_VOIP;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * _audio_sample_size(format);
+ } else {
+ AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ } else { /* AUDIO_DIRECTION_OUT */
+ if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_LOW");
+ period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_FASTMODE;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (samplerate / 10) * _audio_sample_size(format) * channels; /* 100ms */
+ *maxlength = -1;
+ *fragsize = 0;
+ } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_MID");
+ period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_DEFAULT;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (uint32_t) _audio_usec_to_bytes(200000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = -1;
+ } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_HIGH");
+ period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_PLAYBACK;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (uint32_t) _audio_usec_to_bytes(400000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = -1;
+ } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_VOIP");
+ period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ periods_per_buffer = PERIODS_PER_BUFFER_VOIP;
+ *prebuf = 0;
+ *minreq = _audio_usec_to_bytes(20000, samplerate, format, channels);
+ *tlength = _audio_usec_to_bytes(100000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = 0;
+ } else {
+ AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+
+ AUDIO_LOG_INFO("hal-latency - return attr --> prebuf:%d, minreq:%d, tlength:%d, maxlength:%d, fragsize:%d", *prebuf, *minreq, *tlength, *maxlength, *fragsize);
+ return AUDIO_RET_OK;
+}
diff --git a/tizen-audio.h b/tizen-audio.h
new file mode 100644
index 0000000..9fdcafb
--- /dev/null
+++ b/tizen-audio.h
@@ -0,0 +1,236 @@
+#ifndef footizenaudiofoo
+#define footizenaudiofoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/* Error code */
+
+#define AUDIO_IS_ERROR(ret) (ret < 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_NOT_IMPLEMENTED = (int32_t)0x80001004,
+} audio_return_t ;
+
+/* Direction */
+typedef enum audio_direction {
+ AUDIO_DIRECTION_IN, /**< Capture */
+ AUDIO_DIRECTION_OUT, /**< Playback */
+} audio_direction_t;
+
+typedef enum audio_device_api {
+ AUDIO_DEVICE_API_UNKNOWN,
+ AUDIO_DEVICE_API_ALSA,
+ AUDIO_DEVICE_API_BLUEZ,
+} audio_device_api_t;
+
+typedef enum audio_device_param {
+ AUDIO_DEVICE_PARAM_NONE,
+ AUDIO_DEVICE_PARAM_CHANNELS,
+ AUDIO_DEVICE_PARAM_SAMPLERATE,
+ AUDIO_DEVICE_PARAM_FRAGMENT_SIZE,
+ AUDIO_DEVICE_PARAM_FRAGMENT_NB,
+ AUDIO_DEVICE_PARAM_START_THRESHOLD,
+ AUDIO_DEVICE_PARAM_USE_MMAP,
+ AUDIO_DEVICE_PARAM_USE_TSCHED,
+ AUDIO_DEVICE_PARAM_TSCHED_BUF_SIZE,
+ AUDIO_DEVICE_PARAM_SUSPEND_TIMEOUT,
+ AUDIO_DEVICE_PARAM_ALTERNATE_RATE,
+ AUDIO_DEVICE_PARAM_MAX,
+} audio_device_param_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;
+
+/* audio latency */
+static const char* AUDIO_LATENCY_LOW = "low";
+static const char* AUDIO_LATENCY_MID = "mid";
+static const char* AUDIO_LATENCY_HIGH = "high";
+static const char* AUDIO_LATENCY_VOIP = "voip";
+
+typedef struct audio_device_param_info {
+ audio_device_param_t param;
+ union {
+ int64_t s64_v;
+ uint64_t u64_v;
+ int32_t s32_v;
+ uint32_t u32_v;
+ };
+} audio_device_param_info_t;
+
+typedef struct audio_device_alsa_info {
+ char *card_name;
+ uint32_t card_idx;
+ uint32_t device_idx;
+} audio_device_alsa_info_t;
+
+typedef struct audio_device_bluz_info {
+ char *protocol;
+ uint32_t nrec;
+} audio_device_bluez_info_t;
+
+typedef struct audio_device_info {
+ audio_device_api_t api;
+ audio_direction_t direction;
+ char *name;
+ uint8_t is_default_device;
+ union {
+ audio_device_alsa_info_t alsa;
+ audio_device_bluez_info_t bluez;
+ };
+} audio_device_info_t;
+
+typedef struct device_info {
+ const char *type;
+ uint32_t direction;
+ uint32_t id;
+} device_info_t;
+
+typedef struct audio_volume_info {
+ const char *type;
+ const char *gain;
+ uint32_t direction;
+} audio_volume_info_t ;
+
+typedef struct audio_route_info {
+ const char *role;
+ device_info_t *device_infos;
+ uint32_t num_of_devices;
+} audio_route_info_t;
+
+typedef struct audio_route_option {
+ const char *role;
+ const char *name;
+ int32_t value;
+} audio_route_option_t;
+
+typedef struct audio_stream_info {
+ const char *role;
+ uint32_t direction;
+ uint32_t idx;
+} audio_stream_info_t ;
+
+/* Stream */
+
+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_FIXED, /**< Volume type for fixed acoustic level */
+ 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;
+
+/* Overall */
+typedef struct audio_interface {
+ audio_return_t (*init)(void **userdata);
+ audio_return_t (*deinit)(void **userdata);
+ audio_return_t (*get_volume_level_max)(void *userdata, audio_volume_info_t *info, uint32_t *level);
+ audio_return_t (*get_volume_level)(void *userdata, audio_volume_info_t *info, uint32_t *level);
+ audio_return_t (*set_volume_level)(void *userdata, audio_volume_info_t *info, uint32_t level);
+ audio_return_t (*get_volume_value)(void *userdata, audio_volume_info_t *info, uint32_t level, double *value);
+ audio_return_t (*get_volume_mute)(void *userdata, audio_volume_info_t *info, uint32_t *mute);
+ audio_return_t (*set_volume_mute)(void *userdata, audio_volume_info_t *info, uint32_t mute);
+ audio_return_t (*do_route)(void *userdata, audio_route_info_t *info);
+ audio_return_t (*update_route_option)(void *userdata, audio_route_option_t *option);
+ audio_return_t (*update_stream_connection_info) (void *userdata, audio_stream_info_t *info, uint32_t is_connected);
+ audio_return_t (*get_buffer_attr)(void *userdata, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
+ uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
+ /* Interface of PCM device */
+ audio_return_t (*pcm_open)(void *userdata, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+ audio_return_t (*pcm_start)(void *userdata, void *pcm_handle);
+ audio_return_t (*pcm_stop)(void *userdata, void *pcm_handle);
+ audio_return_t (*pcm_close)(void *userdata, void *pcm_handle);
+ audio_return_t (*pcm_avail)(void *userdata, void *pcm_handle, uint32_t *avail);
+ audio_return_t (*pcm_write)(void *userdata, void *pcm_handle, const void *buffer, uint32_t frames);
+ audio_return_t (*pcm_read)(void *userdata, void *pcm_handle, void *buffer, uint32_t frames);
+ audio_return_t (*pcm_get_fd)(void *userdata, void *pcm_handle, int *fd);
+ audio_return_t (*pcm_recover)(void *userdata, void *pcm_handle, int revents);
+ audio_return_t (*pcm_get_params)(void *userdata, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+ audio_return_t (*pcm_set_params)(void *userdata, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+} audio_interface_t;
+
+audio_return_t audio_init(void **userdata);
+audio_return_t audio_deinit(void **userdata);
+audio_return_t audio_get_volume_level_max(void *userdata, audio_volume_info_t *info, uint32_t *level);
+audio_return_t audio_get_volume_level(void *userdata, audio_volume_info_t *info, uint32_t *level);
+audio_return_t audio_set_volume_level(void *userdata, audio_volume_info_t *info, uint32_t level);
+audio_return_t audio_get_volume_value(void *userdata, audio_volume_info_t *info, uint32_t level, double *value);
+audio_return_t audio_get_volume_mute(void *userdata, audio_volume_info_t *info, uint32_t *mute);
+audio_return_t audio_set_volume_mute(void *userdata, audio_volume_info_t *info, uint32_t mute);
+audio_return_t audio_do_route(void *userdata, audio_route_info_t *info);
+audio_return_t audio_update_route_option(void *userdata, audio_route_option_t *option);
+audio_return_t audio_update_stream_connection_info(void *userdata, audio_stream_info_t *info, uint32_t is_connected);
+audio_return_t audio_get_buffer_attr(void *userdata, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
+ uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
+audio_return_t audio_pcm_open(void *userdata, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_t audio_pcm_start(void *userdata, void *pcm_handle);
+audio_return_t audio_pcm_stop(void *userdata, void *pcm_handle);
+audio_return_t audio_pcm_close(void *userdata, void *pcm_handle);
+audio_return_t audio_pcm_avail(void *userdata, void *pcm_handle, uint32_t *avail);
+audio_return_t audio_pcm_write(void *userdata, void *pcm_handle, const void *buffer, uint32_t frames);
+audio_return_t audio_pcm_read(void *userdata, void *pcm_handle, void *buffer, uint32_t frames);
+audio_return_t audio_pcm_get_fd(void *userdata, void *pcm_handle, int *fd);
+audio_return_t audio_pcm_recover(void *userdata, void *pcm_handle, int revents);
+audio_return_t audio_pcm_get_params(void *userdata, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+audio_return_t audio_pcm_set_params(void *userdata, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+#endif