Initialization audio HAL for SC7727 (target:TM1) 59/52159/5
authorSangchul Lee <sc11.lee@samsung.com>
Thu, 19 Nov 2015 10:34:33 +0000 (19:34 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Mon, 23 Nov 2015 03:05:06 +0000 (12:05 +0900)
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>
14 files changed:
LICENSE.Apache-2.0 [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NOTICE [new file with mode: 0644]
audio-hal-sc7727.manifest [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
packaging/audio-hal-sc7727.spec [new file with mode: 0644]
tizen-audio-device.c [new file with mode: 0644]
tizen-audio-internal.h [new file with mode: 0644]
tizen-audio-ucm.c [new file with mode: 0644]
tizen-audio-util.c [new file with mode: 0644]
tizen-audio-volume.c [new file with mode: 0644]
tizen-audio.c [new file with mode: 0644]
tizen-audio.h [new file with mode: 0644]

diff --git a/LICENSE.Apache-2.0 b/LICENSE.Apache-2.0
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -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 (file)
index 0000000..1145f10
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..8e229ef
--- /dev/null
@@ -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 (file)
index 0000000..3b0c487
--- /dev/null
@@ -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 (file)
index 0000000..ac15050
--- /dev/null
@@ -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 (file)
index 0000000..799dbb4
--- /dev/null
@@ -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 (file)
index 0000000..4bf51ec
--- /dev/null
@@ -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 (file)
index 0000000..ba8cc5e
--- /dev/null
@@ -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 (file)
index 0000000..83785c0
--- /dev/null
@@ -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 (file)
index 0000000..e841f4a
--- /dev/null
@@ -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 (file)
index 0000000..b7df609
--- /dev/null
@@ -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 (file)
index 0000000..9fdcafb
--- /dev/null
@@ -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