summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE.Apache-2.0202
-rw-r--r--Makefile.am14
-rw-r--r--NOTICE3
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac55
-rw-r--r--packaging/audio-hal-sc7727.spec57
-rw-r--r--tizen-audio-device.c698
-rw-r--r--tizen-audio-internal.h380
-rw-r--r--tizen-audio-modem.c1073
-rw-r--r--tizen-audio-session.c245
-rw-r--r--tizen-audio-stream.c638
-rw-r--r--tizen-audio-ucm.c466
-rw-r--r--tizen-audio-util.c357
-rw-r--r--tizen-audio.c131
-rw-r--r--tizen-audio.h279
-rw-r--r--vb_control_parameters.h116
16 files changed, 4724 insertions, 0 deletions
diff --git a/LICENSE.Apache-2.0 b/LICENSE.Apache-2.0
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.Apache-2.0
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..46b22e4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,14 @@
+lib_LTLIBRARIES = libtizen-audio.la
+
+libtizen_audio_la_SOURCES = tizen-audio.c \
+ tizen-audio-session.c \
+ tizen-audio-device.c \
+ tizen-audio-stream.c \
+ tizen-audio-ucm.c \
+ tizen-audio-modem.c \
+ tizen-audio-util.c
+libtizen_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
+libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS) $(TAPI_LIBS) -lexpat
+libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) $(TAPI_CFLAGS)
+libtizen_audio_la_CFLAGS += -DUSE_DLOG
+
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..ccdad52
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE file for Apache License terms and conditions.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..8e229ef
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# autogen.sh -- Autotools bootstrapping
+#
+
+libtoolize --copy --force
+aclocal && \
+autoheader && \
+autoconf && \
+automake --add-missing --copy
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..e6257d8
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,55 @@
+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)
+
+PKG_CHECK_MODULES(VCONF, vconf)
+AC_SUBST(VCONF_CFLAGS)
+AC_SUBST(VCONF_LIBS)
+
+PKG_CHECK_MODULES(INIPARSER, iniparser)
+AC_SUBST(INIPARSER_CFLAGS)
+AC_SUBST(INIPARSER_LIBS)
+
+PKG_CHECK_MODULES(DLOG, dlog)
+AC_SUBST(DLOG_CFLAGS)
+AC_SUBST(DLOG_LIBS)
+
+PKG_CHECK_MODULES(TAPI, tapi)
+AC_SUBST(TAPI_CFLAGS)
+AC_SUBST(TAPI_LIBS)
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+
+
+AC_CONFIG_FILES([ \
+ Makefile
+ ])
+AC_OUTPUT
diff --git a/packaging/audio-hal-sc7727.spec b/packaging/audio-hal-sc7727.spec
new file mode 100644
index 0000000..cc0073c
--- /dev/null
+++ b/packaging/audio-hal-sc7727.spec
@@ -0,0 +1,57 @@
+Name: audio-hal-sc7727
+Summary: TIZEN Audio HAL for SC7727
+Version: 0.3.17
+Release: 0
+Group: System/Libraries
+License: Apache-2.0
+URL: http://tizen.org
+Source0: audio-hal-sc7727-%{version}.tar.gz
+ExclusiveArch: %arm
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(iniparser)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(alsa)
+BuildRequires: pkgconfig(tapi)
+BuildRequires: expat-devel
+Provides: libtizen-audio.so
+
+%if ("%{tizen_target_name}" != "Z130H" && "%{tizen_target_name}" != "Z300H")
+ExcludeArch: %{arm}
+%endif
+
+%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"
+
+%if "%{tizen_target_name}" == "Z300H"
+export CFLAGS+=" -DUSE_FMRADIO_V4L2_SPRD"
+%endif
+
+%autogen
+%configure
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE.Apache-2.0 %{buildroot}/usr/share/license/%{name}
+%make_install
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+/usr/lib/libtizen-audio.so
+/usr/share/license/%{name}
diff --git a/tizen-audio-device.c b/tizen-audio-device.c
new file mode 100644
index 0000000..ef0a29c
--- /dev/null
+++ b/tizen-audio-device.c
@@ -0,0 +1,698 @@
+/*
+ * 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"
+
+audio_return_t _audio_device_init (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ am->device.active_in = AUDIO_DEVICE_IN_NONE;
+ am->device.active_out = AUDIO_DEVICE_OUT_NONE;
+ am->device.route_flag = AUDIO_ROUTE_FLAG_NONE;
+ am->device.pcm_in = NULL;
+ am->device.pcm_out = NULL;
+ pthread_mutex_init(&am->device.pcm_lock, NULL);
+ am->device.pcm_count = 0;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ am->device.fmradio_pcm_out = NULL;
+#endif
+
+ 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;
+}
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+audio_return_t _fmradio_pcm_open (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+ const char *device_name = NULL;
+ audio_pcm_sample_spec_t sample_spec;
+ uint8_t use_mmap = 0;
+
+ sample_spec.rate = 44100;
+ sample_spec.channels = 2;
+ sample_spec.format = SND_PCM_FORMAT_S16_LE;
+
+ /* open playback device */
+ _audio_ucm_get_device_name(am, AUDIO_USE_CASE_VERB_FMRADIO, AUDIO_DIRECTION_OUT, &device_name);
+
+ if (device_name) {
+ if((ret = audio_alsa_pcm_open((void *)am, (void **)&am->device.fmradio_pcm_out, (char *)device_name, AUDIO_DIRECTION_OUT, 0)) != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("[%s] out pcm_open failed", device_name);
+ goto error_exit;
+ }
+ AUDIO_LOG_INFO("[%s] out pcm_open success:%p", device_name, am->device.fmradio_pcm_out);
+
+ if ((ret = _audio_pcm_set_hw_params(am->device.fmradio_pcm_out, &sample_spec, &use_mmap, NULL, NULL)) != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("[%s] out __set_pcm_hw_params failed", device_name);
+ audio_alsa_pcm_close((void *)am, am->device.fmradio_pcm_out);
+ am->device.fmradio_pcm_out = NULL;
+ goto error_exit;
+ }
+ free((void *)device_name);
+ }
+
+ return AUDIO_RET_OK;
+
+error_exit:
+ if (device_name)
+ free((void *)device_name);
+
+ return AUDIO_ERR_RESOURCE;
+}
+
+audio_return_t _fmradio_pcm_close (audio_mgr_t *am)
+{
+ /* close playback device */
+ if (am->device.fmradio_pcm_out) {
+ audio_alsa_pcm_close((void *)am, am->device.fmradio_pcm_out);
+ am->device.fmradio_pcm_out = NULL;
+ }
+ return AUDIO_RET_OK;
+}
+#endif
+
+static void __free_device_info (audio_device_info_t *device_info)
+{
+ if (device_info->name) {
+ free(device_info->name);
+ device_info->name = NULL;
+ }
+ if (device_info->api == AUDIO_DEVICE_API_ALSA) {
+ if (device_info->alsa.card_name) {
+ free(device_info->alsa.card_name);
+ device_info->alsa.card_name = NULL;
+ }
+ }
+}
+
+static void __load_n_open_device_with_params (audio_mgr_t *am, audio_device_info_t *device_info, int load_only)
+{
+ audio_device_param_info_t params[AUDIO_DEVICE_PARAM_MAX];
+ int dev_param_count = 0;
+
+ AUDIO_RETURN_IF_FAIL(am);
+ AUDIO_RETURN_IF_FAIL(device_info);
+ AUDIO_RETURN_IF_FAIL(am->cb_intf.load_device);
+ AUDIO_RETURN_IF_FAIL(am->cb_intf.open_device);
+
+ memset(&params[0], 0, sizeof(audio_device_param_info_t) * AUDIO_DEVICE_PARAM_MAX);
+
+ if (device_info->api == AUDIO_DEVICE_API_ALSA) {
+ /* 6 = "hw: ,idx */
+ if ((device_info->name = malloc(strlen(device_info->alsa.card_name) + 6)) != NULL){
+ snprintf(device_info->name, strlen(device_info->alsa.card_name) + 6,
+ "hw:%s,%d", device_info->alsa.card_name, device_info->alsa.device_idx);
+ }
+ if (device_info->direction == AUDIO_DIRECTION_OUT) {
+ /* ALSA playback */
+ if (!strncmp(device_info->alsa.card_name, ALSA_DEFAULT_CARD, strlen(ALSA_DEFAULT_CARD))) {
+ /* default card */
+ switch (device_info->alsa.device_idx) {
+ /* default device */
+ case 0:
+ device_info->is_default_device = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SUSPEND_TIMEOUT;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_TSCHED_BUF_SIZE;
+ params[dev_param_count++].u32_v = 35280;
+ AUDIO_LOG_INFO("HiFi Device");
+ break;
+ case 1:
+ /* VOICE PCM. */
+ break;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ /* FM device */
+ case 4:
+ AUDIO_LOG_INFO("Digital FM device");
+ break;
+#endif
+ default:
+ AUDIO_LOG_INFO("Unknown Playback Device");
+ break;
+ }
+ } else if (!strncmp(device_info->alsa.card_name, ALSA_SAUDIOVOIP_CARD, strlen(ALSA_SAUDIOVOIP_CARD))) {
+ device_info->is_default_device = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_CHANNELS;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_FRAGMENT_SIZE;
+ params[dev_param_count++].u32_v = 640;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_FRAGMENT_NB;
+ params[dev_param_count++].u32_v = 2;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SAMPLERATE;
+ params[dev_param_count++].u32_v = 8000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_ALTERNATE_RATE;
+ params[dev_param_count++].u32_v = 8000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_USE_TSCHED;
+ params[dev_param_count++].u32_v = 0;
+ } else if (!strncmp(device_info->alsa.card_name, ALSA_VIRTUAL_CARD, strlen(ALSA_VIRTUAL_CARD))) {
+ /* virtual card */
+ device_info->is_default_device = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SAMPLERATE;
+ params[dev_param_count++].u32_v = 16000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_CHANNELS;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_USE_TSCHED;
+ params[dev_param_count++].u32_v = 0;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SUSPEND_TIMEOUT;
+ params[dev_param_count++].u32_v = 0;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_ALTERNATE_RATE;
+ params[dev_param_count++].u32_v = 16000;
+ }
+ } else if (device_info->direction == AUDIO_DIRECTION_IN) {
+ /* ALSA capture */
+ if (!strncmp(device_info->alsa.card_name, ALSA_DEFAULT_CARD, strlen(ALSA_DEFAULT_CARD))) {
+ /* default card */
+ switch (device_info->alsa.device_idx) {
+ /* default device */
+ case 0:
+ device_info->is_default_device = 1;
+ /* use mmap */
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_USE_MMAP;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SAMPLERATE;
+ params[dev_param_count++].u32_v = (am->session.is_radio_on) ? 44100 : 48000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_ALTERNATE_RATE;
+ params[dev_param_count++].u32_v = (am->session.is_radio_on) ? 44100 : 48000;
+ break;
+ default:
+ AUDIO_LOG_INFO("Unknown Capture Device");
+ break;
+ }
+ } else if (!strncmp(device_info->alsa.card_name, ALSA_SAUDIOVOIP_CARD, strlen(ALSA_SAUDIOVOIP_CARD))) {
+ device_info->is_default_device = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SAMPLERATE;
+ params[dev_param_count++].u32_v = 8000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_CHANNELS;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_FRAGMENT_SIZE;
+ params[dev_param_count++].u32_v = 640;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_FRAGMENT_NB;
+ params[dev_param_count++].u32_v = 8;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_USE_TSCHED;
+ params[dev_param_count++].u32_v = 0;
+ } else if (!strncmp(device_info->alsa.card_name, ALSA_VIRTUAL_CARD, strlen(ALSA_VIRTUAL_CARD))) {
+ /* virtual card */
+ device_info->is_default_device = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SAMPLERATE;
+ params[dev_param_count++].u32_v = 16000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_CHANNELS;
+ params[dev_param_count++].u32_v = 1;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_USE_TSCHED;
+ params[dev_param_count++].u32_v = 0;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_SUSPEND_TIMEOUT;
+ params[dev_param_count++].u32_v = 0;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_ALTERNATE_RATE;
+ params[dev_param_count++].u32_v = 16000;
+ }
+ }
+
+ AUDIO_LOG_INFO("open alsa %s device hw:%s,%d", (device_info->direction == AUDIO_DIRECTION_IN) ? "capture" : "playback",
+ device_info->alsa.card_name, device_info->alsa.device_idx);
+ }
+
+ if (load_only) {
+ am->cb_intf.load_device(am->platform_data, device_info, &params[0]);
+ } else {
+ am->cb_intf.open_device(am->platform_data, device_info, &params[0]);
+ }
+}
+
+void _load_n_open_device_from_ucm (audio_mgr_t *am, const char *verb, int load_only)
+{
+ audio_device_info_t device_info_list[AUDIO_DEVICE_INFO_LIST_MAX];
+ int i, dev_info_count = 0;
+
+ AUDIO_RETURN_IF_FAIL(am);
+
+ memset((void *)&device_info_list[0], 0, sizeof(audio_device_info_t) * AUDIO_DEVICE_INFO_LIST_MAX);
+ /* fill device params & open device */
+ dev_info_count = _audio_ucm_fill_device_info_list(am, &device_info_list[0], verb);
+ for (i = 0; i < dev_info_count; i++) {
+ __load_n_open_device_with_params(am, &device_info_list[i], load_only);
+ __free_device_info(&device_info_list[i]);
+ }
+}
+
+void _close_n_unload_device_from_ucm (audio_mgr_t *am, const char *verb, int force_unload)
+{
+ audio_device_info_t device_info_list[AUDIO_DEVICE_INFO_LIST_MAX];
+ int i, dev_info_count = 0;
+
+ AUDIO_RETURN_IF_FAIL(am);
+ AUDIO_RETURN_IF_FAIL(am->cb_intf.close_device);
+ AUDIO_RETURN_IF_FAIL(am->cb_intf.unload_device);
+
+ memset((void *)&device_info_list[0], 0, sizeof(audio_device_info_t) * AUDIO_DEVICE_INFO_LIST_MAX);
+ /* fill device params & open device */
+ dev_info_count = _audio_ucm_fill_device_info_list(am, &device_info_list[0], verb);
+ for (i = 0; i < dev_info_count; i++) {
+ if (!force_unload) {
+ am->cb_intf.close_device(am->platform_data, &device_info_list[i]);
+ } else {
+ am->cb_intf.unload_device(am->platform_data, &device_info_list[i]);
+ }
+ __free_device_info(&device_info_list[i]);
+ }
+}
+
+void _open_virtual_device (audio_mgr_t *am)
+{
+ audio_device_info_t device_info;
+
+ AUDIO_RETURN_IF_FAIL(am);
+
+ if (am->cb_intf.open_device) {
+ /* open Rx device */
+ memset(&device_info, 0x00, sizeof(audio_device_info_t));
+ device_info.api = AUDIO_DEVICE_API_ALSA;
+ device_info.alsa.device_idx = 0;
+ device_info.alsa.card_name = strdup(ALSA_VIRTUAL_CARD);
+ device_info.alsa.card_idx = snd_card_get_index(device_info.alsa.card_name);
+ device_info.direction = AUDIO_DIRECTION_OUT;
+ __load_n_open_device_with_params(am, &device_info, 0);
+ __free_device_info(&device_info);
+ /* open Tx device */
+ memset(&device_info, 0x00, sizeof(audio_device_info_t));
+ device_info.api = AUDIO_DEVICE_API_ALSA;
+ device_info.alsa.device_idx = 0;
+ device_info.alsa.card_name = strdup(ALSA_VIRTUAL_CARD);
+ device_info.alsa.card_idx = snd_card_get_index(device_info.alsa.card_name);
+ device_info.direction = AUDIO_DIRECTION_IN;
+ __load_n_open_device_with_params(am, &device_info, 0);
+ __free_device_info(&device_info);
+ }
+}
+
+static audio_return_t __set_route_ap_playback_capture (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int dev_idx = 0;
+ int mod_idx = 0;
+ const char *verb = NULL;
+ const char *devices[MAX_DEVICES] = {NULL,};
+ const char *modifiers[MAX_MODIFIERS] = {NULL,};
+
+ verb = AUDIO_USE_CASE_VERB_HIFI;
+
+ if (route_flag & AUDIO_ROUTE_FLAG_MUTE_POLICY) {
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ } else if (route_flag & AUDIO_ROUTE_FLAG_DUAL_OUT) {
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ if (device_out == AUDIO_DEVICE_OUT_MIRRORING) {
+ AUDIO_LOG_INFO("Skip WFD enable during DUAL path");
+ }
+ } else {
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ if (am->session.is_radio_on == 1 && am->session.is_recording != 1) {
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_FM_SPEAKER;
+ } else {
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ }
+ break;
+ case AUDIO_DEVICE_OUT_RECEIVER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HANDSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY:
+ if (am->session.is_radio_on == 1) {
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_FM_HEADSET;
+ } else {
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ }
+ break;
+ /* even BT SCO is opened by call app, we cannot use BT SCO on HiFi verb */
+ case AUDIO_DEVICE_OUT_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (am->session.is_radio_on == 0 || am->session.is_recording == 1) {
+ switch (device_in) {
+ case AUDIO_DEVICE_IN_MIC:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_MAIN_MIC;
+ break;
+ case AUDIO_DEVICE_IN_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET_MIC;
+ break;
+ /* even BT SCO is opened by call app, we cannot use BT SCO on HiFi verb */
+ case AUDIO_DEVICE_IN_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_MAIN_MIC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (am->session.is_radio_on == 1) {
+ /* FM radio don't want to route BT headset */
+ if(device_out != AUDIO_DEVICE_OUT_SPEAKER && device_out != AUDIO_DEVICE_OUT_WIRED_ACCESSORY) {
+ AUDIO_LOG_INFO("not supported devices. device_out(%d)", device_out);
+ audio_ret = AUDIO_ERR_PARAMETER;
+ return audio_ret;
+ }
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_FMRADIO_CORE;
+ }
+
+ /* TODO. Handle voice recognition when seperate devices are available */
+ audio_ret = _audio_ucm_update_use_case(am, verb, devices, modifiers);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ return audio_ret;
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _set_route_voicecall (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int dev_idx = 0;
+ const char *verb = NULL;
+ const char *devices[MAX_DEVICES] = {NULL,};
+
+ verb = AUDIO_USE_CASE_VERB_VOICECALL;
+
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ /* FIXME: WB handling is needed */
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_RECEIVER:
+ /* FIXME: WB handling is needed */
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HANDSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_BT_HEADSET;
+ break;
+ default:
+ break;
+ }
+
+ switch (device_in) {
+ case AUDIO_DEVICE_IN_MIC:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_MAIN_MIC;
+ break;
+ case AUDIO_DEVICE_IN_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET_MIC;
+ break;
+ default:
+ break;
+ }
+
+ /* FIXME. Get network info and configure rate in pcm device */
+ audio_ret = _audio_ucm_update_use_case(am, verb, devices, NULL);
+
+ return audio_ret;
+}
+
+static audio_return_t __set_route_voip (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ int dev_idx = 0;
+ const char *verb = NULL;
+ const char *devices[MAX_DEVICES] = {NULL,};
+
+ verb = AUDIO_USE_CASE_VERB_HIFI; /* Modify later to use VIRTUALAUDIO to enable echo cancellation */
+
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_RECEIVER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HANDSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_BT_HEADSET;
+ break;
+ default:
+ break;
+ }
+
+ switch (device_in) {
+ case AUDIO_DEVICE_IN_MIC:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_MAIN_MIC;
+ break;
+ case AUDIO_DEVICE_IN_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET_MIC;
+ break;
+ case AUDIO_DEVICE_IN_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_BT_MIC;
+ break;
+ default:
+ break;
+ }
+
+ return _audio_ucm_update_use_case(am, verb, devices, NULL);
+}
+
+audio_return_t _set_route_videocall (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int dev_idx = 0;
+ const char *devices[MAX_DEVICES] = {NULL,};
+
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_RECEIVER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HANDSET;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ break;
+ case AUDIO_DEVICE_OUT_BT_SCO:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_BT_HEADSET;
+ break;
+ default:
+ break;
+ }
+
+ switch (device_in) {
+ case AUDIO_DEVICE_IN_MIC:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_MAIN_MIC;
+ break;
+ case AUDIO_DEVICE_IN_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET_MIC;
+ break;
+ default:
+ break;
+ }
+ audio_ret = _audio_ucm_update_use_case(am, AUDIO_USE_CASE_VERB_VIDEOCALL, devices, NULL);
+
+ return audio_ret;
+}
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+audio_return_t __set_route_fmradio (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ int dev_idx = 0;
+ const char *verb = NULL;
+ const char *devices[MAX_DEVICES] = {NULL,};
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ verb = AUDIO_USE_CASE_VERB_FMRADIO;
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_SPEAKER;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY:
+ devices[dev_idx++] = AUDIO_USE_CASE_DEV_HEADSET;
+ _set_volume_level_fmradio(am,0);
+ break;
+ default:
+ AUDIO_LOG_INFO("not supported devices. device_out(%d)", device_out);
+ return AUDIO_ERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ audio_ret = _audio_ucm_update_use_case(am, verb, devices, NULL);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ return audio_ret;
+ }
+
+ return audio_ret;
+}
+#endif
+
+audio_return_t _reset_route (audio_mgr_t *am, int need_inactive)
+{
+ const char *devices[MAX_DEVICES] = {NULL,};
+ const char *modifiers[MAX_MODIFIERS] = {NULL,};
+
+ if(need_inactive) {
+ _audio_ucm_update_use_case(am, AUDIO_USE_CASE_VERB_INACTIVE, devices, modifiers);
+ }
+ _audio_ucm_update_use_case(am, AUDIO_USE_CASE_VERB_HIFI, devices, modifiers);
+ __set_route_ap_playback_capture(am, am->device.active_in, am->device.active_out, 0);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_set_route (void *userdata, uint32_t session, uint32_t subsession, uint32_t device_in, uint32_t device_out, uint32_t route_flag)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ int i, dev_info_count = 0;
+ audio_device_info_t device_info_list[AUDIO_DEVICE_INFO_LIST_MAX];
+
+ am->device.active_in = device_in;
+ am->device.active_out = device_out;
+ am->device.route_flag = route_flag;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("session:%d,%d in:%d out:%d flag:0x%x", session, subsession, device_in, device_out, route_flag);
+
+ if ((session == AUDIO_SESSION_VOICECALL) && (subsession == AUDIO_SUBSESSION_VOICE)) {
+ if (_audio_modem_is_call_connected(am)) {
+ audio_ret = _set_route_voicecall(am, device_in, device_out, route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+ }
+ } else {
+ AUDIO_LOG_DEBUG("skip route before call connected");
+ return AUDIO_RET_OK;
+ }
+ } else if ((session == AUDIO_SESSION_VOIP) && (subsession == AUDIO_SUBSESSION_VOICE)) {
+ audio_ret = __set_route_voip(am, device_in, device_out, route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set voip route return 0x%x", audio_ret);
+ }
+ } else if ((session == AUDIO_SESSION_VIDEOCALL) && (subsession == AUDIO_SUBSESSION_VOICE) && _audio_modem_is_call_connected(am)) {
+ audio_ret = _set_route_videocall(am, device_in, device_out, route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set videocall route return 0x%x", audio_ret);
+ }
+ }
+#ifdef USE_FMRADIO_V4L2_SPRD
+ else if(session == AUDIO_SESSION_FMRADIO) {
+ audio_ret = __set_route_fmradio(am, device_in, device_out, route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set fm route return 0x%x", audio_ret);
+ }
+ }
+#endif
+ else {
+ audio_ret = __set_route_ap_playback_capture(am, device_in, device_out, route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
+ }
+ }
+
+ if (!AUDIO_IS_ERROR(audio_ret)) {
+ memset((void *)&device_info_list[0], 0, sizeof(audio_device_info_t) * AUDIO_DEVICE_INFO_LIST_MAX);
+ /* fill device params & open device */
+ dev_info_count = _audio_ucm_fill_device_info_list(am, &device_info_list[0], NULL);
+ for (i = 0; i < dev_info_count; i++) {
+ __load_n_open_device_with_params(am, &device_info_list[i], 0);
+ }
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_set_route_info(void *userdata, const char* key, const char* value)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ int mixer_value = 0;
+
+ if(key == NULL || value == NULL)
+ return AUDIO_ERR_PARAMETER;
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+ if(!strncmp(key, "fm_mute", strlen(key))) {
+ mixer_value = atoi(value);
+ audio_ret = _audio_mixer_control_set_value(am, MIXER_FMRADIO_MUTE, mixer_value);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_MUTE);
+ }
+ }
+#endif
+
+ return audio_ret;
+}
+
+audio_return_t audio_alsa_pcm_open (void *userdata, void **pcm_handle, char *device_name, uint32_t direction, int mode)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+// pthread_mutex_lock(&am->device.pcm_lock);
+ 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));
+ pthread_mutex_unlock(&am->device.pcm_lock);
+ return AUDIO_ERR_RESOURCE;
+ }
+ am->device.pcm_count++;
+ AUDIO_LOG_INFO("PCM handle 0x%x(%s,%s) opened(count:%d)", *pcm_handle, device_name, (direction == AUDIO_DIRECTION_OUT) ? "playback" : "capture", am->device.pcm_count);
+// pthread_mutex_unlock(&am->device.pcm_lock);
+
+ return audio_ret;
+}
+
+audio_return_t audio_alsa_pcm_close (void *userdata, void *pcm_handle)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ int err;
+
+ AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
+// pthread_mutex_lock(&am->device.pcm_lock);
+ if ((err = snd_pcm_close(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
+ pthread_mutex_unlock(&am->device.pcm_lock);
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ am->device.pcm_count--;
+ AUDIO_LOG_INFO("PCM handle close success (count:%d)", am->device.pcm_count);
+// pthread_mutex_unlock(&am->device.pcm_lock);
+
+ return audio_ret;
+}
diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h
new file mode 100644
index 0000000..2232d26
--- /dev/null
+++ b/tizen-audio-internal.h
@@ -0,0 +1,380 @@
+#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>
+#include <pthread.h>
+#include <use-case.h>
+#include "tizen-audio.h"
+#include "vb_control_parameters.h"
+#include "tapi_common.h"
+
+/* Debug */
+
+//#define AUDIO_DEBUG
+#define PROPERTY_VALUE_MAX 92
+#define BUF_SIZE 1024
+#define AUDIO_XML_PATH "/usr/etc/audio_hw.xml"
+#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)
+
+/* Verbs */
+#define AUDIO_USE_CASE_VERB_INACTIVE "Inactive"
+#define AUDIO_USE_CASE_VERB_HIFI "HiFi"
+#define AUDIO_USE_CASE_VERB_VOICECALL "Voice"
+#define AUDIO_USE_CASE_VERB_LOOPBACK "Loopback"
+#ifdef USE_FMRADIO_V4L2_SPRD
+#define AUDIO_USE_CASE_VERB_FMRADIO "DigitalFM"
+#else
+#define AUDIO_USE_CASE_VERB_FMRADIO "FM"
+#endif
+#define AUDIO_USE_CASE_VERB_VIDEOCALL "Video"
+
+/* Devices : Normal */
+#define AUDIO_USE_CASE_DEV_SPEAKER "Speaker"
+#define AUDIO_USE_CASE_DEV_HANDSET "Earpiece"
+#define AUDIO_USE_CASE_DEV_HEADSET "Headphones"
+#define AUDIO_USE_CASE_DEV_HEADSET_3POLE "Headphones"
+#define AUDIO_USE_CASE_DEV_BT_HEADSET "Bluetooth"
+#define AUDIO_USE_CASE_DEV_LINEOUT "Line"
+#define AUDIO_USE_CASE_DEV_FMRADIO "FM"
+#define AUDIO_USE_CASE_DEV_FMRADIO_CORE "FM_Core"
+
+#define AUDIO_USE_CASE_DEV_MAIN_MIC "MainMic"
+#define AUDIO_USE_CASE_DEV_SUB_MIC "SubMic"
+#define AUDIO_USE_CASE_DEV_HEADSET_MIC "HeadsetMic"
+#define AUDIO_USE_CASE_DEV_BT_MIC "BT Mic"
+
+/* Modifiers */
+#define AUDIO_USE_CASE_MODIFIER_VOICE "VoiceSearch"
+#define AUDIO_USE_CASE_MODIFIER_CAMCORDING "Camcording"
+#define AUDIO_USE_CASE_MODIFIER_RINGTONE "Ringtone"
+
+#define AUDIO_USE_CASE_MODIFIER_FMRADIO "PlayFM"
+#define AUDIO_USE_CASE_MODIFIER_FM_SPEAKER "FM_Speaker"
+#define AUDIO_USE_CASE_MODIFIER_FM_HEADSET "FM_Headphone"
+#define MIXER_VBC_SWITCH "VBC Switch"
+#ifdef USE_FMRADIO_V4L2_SPRD
+#define MIXER_FMRADIO_L_VOLUME "VBC STR DG Set"
+#define MIXER_FMRADIO_R_VOLUME "VBC STL DG Set"
+#define MIXER_FMRADIO_MUTE "Digital FM Function"
+#endif
+#define FM_IIS 0x10
+#define VBC_TD_CHANNELID 0
+#define VBC_ARM_CHANNELID 2
+#define vbc_thread_new pthread_create
+#define streq !strcmp
+#define strneq strcmp
+
+/* pin_switch */
+#define PIN_SWITCH_IIS0_SYS_SEL "IIS0 pin select"
+#define PIN_SWITCH_IIS0_AP_ID 0
+#define PIN_SWITCH_IIS0_CP0_ID 1
+#define PIN_SWITCH_IIS0_CP1_ID 2
+#define PIN_SWITCH_IIS0_CP2_ID 3
+#define PIN_SWITCH_IIS0_VBC_ID 4
+
+#define PIN_SWITCH_BT_IIS_SYS_SEL "BT IIS pin select"
+#define PIN_SWITCH_BT_IIS_CP0_IIS0_ID 0
+#define PIN_SWITCH_BT_IIS_CP1_IIS0_ID 4
+#define PIN_SWITCH_BT_IIS_AP_IIS0_ID 8
+
+#define PIN_SWITCH_BT_IIS_CON_SWITCH "BT IIS con switch"
+
+#define ALSA_DEFAULT_CARD "sprdphone"
+#define ALSA_VIRTUAL_CARD "VIRTUALAUDIOW"
+#define VBPIPE_DEVICE "/dev/spipe_w6"
+#define VBPIPE_VOIP_DEVICE "/dev/spipe_w4"
+#define MUX_DEVICE "/dev/stty_w0"
+#define ALSA_SAUDIOVOIP_CARD "saudiovoip"
+#define VOICE_PCM_DEVICE "hw:sprdphone,1"
+#define VBC_CMD_TAG "VBC"
+#define MESSAGE_OK "OK"
+#define MAX_DEVICES 5
+#define MAX_MODIFIERS 5
+
+/* type definitions */
+typedef signed char int8_t;
+
+/* pcm */
+struct config_parse_state {
+ audio_modem_t *modem_info;
+ /* To do : pga control setting*/
+ /* struct audio_pga *pga; */
+ /* struct pga_profile *profile; */
+ /* struct pga_attribute_item *attribute_item; */
+};
+
+typedef struct {
+ snd_pcm_format_t format;
+ uint32_t rate;
+ uint8_t channels;
+} audio_pcm_sample_spec_t;
+
+/* Session */
+typedef struct audio_session_mgr {
+ audio_session_t session;
+ audio_subsession_t subsession;
+ uint32_t is_recording;
+ uint32_t is_radio_on;
+ uint32_t is_call_session;
+} audio_session_mgr_t;
+
+/* Device */
+
+typedef struct audio_device_mgr {
+ audio_device_in_t active_in;
+ audio_device_out_t active_out;
+ uint32_t route_flag;
+ snd_pcm_t *pcm_in;
+ snd_pcm_t *pcm_out;
+ pthread_mutex_t pcm_lock;
+ uint32_t pcm_count;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ snd_pcm_t *fmradio_pcm_out;
+#endif
+} audio_device_mgr_t;
+
+/* Stream */
+
+#define AUDIO_VOLUME_LEVEL_MAX 16
+
+typedef struct audio_volume_gain_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_gain_table_t;
+
+enum {
+ AUDIO_VOLUME_DEVICE_SPEAKER,
+ AUDIO_VOLUME_DEVICE_RECEIVER,
+ AUDIO_VOLUME_DEVICE_EARJACK,
+ AUDIO_VOLUME_DEVICE_BT_SCO,
+ AUDIO_VOLUME_DEVICE_BT_A2DP,
+ AUDIO_VOLUME_DEVICE_DOCK,
+ AUDIO_VOLUME_DEVICE_HDMI,
+ AUDIO_VOLUME_DEVICE_MIRRORING,
+ AUDIO_VOLUME_DEVICE_USB,
+ AUDIO_VOLUME_DEVICE_MULTIMEDIA_DOCK,
+ AUDIO_VOLUME_DEVICE_MAX,
+};
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+#define FM_VOLUME_MAX 16
+#endif
+
+typedef struct audio_stream_mgr {
+ uint32_t volume_level[AUDIO_VOLUME_TYPE_MAX];
+ audio_volume_gain_table_t *volume_gain_table;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ int fmradio_volume_table[FM_VOLUME_MAX];
+#endif
+} audio_stream_mgr_t;
+
+typedef struct audio_ucm_mgr {
+ snd_use_case_mgr_t* uc_mgr;
+ pthread_mutex_t mutex;
+} audio_ucm_mgr_t;
+
+typedef struct audio_modem_mgr {
+
+ struct {
+ pthread_t thread_handle;
+ pthread_t voip_thread_handle;
+ snd_pcm_t *voice_pcm_handle_p;
+ snd_pcm_t *voice_pcm_handle_c;
+ int exit_vbc_thread;
+ int vbpipe_fd;
+ int vbpipe_voip_fd;
+ unsigned short vbpipe_count;
+ } vbc;
+
+ struct {
+ int fd;
+ } at_cmd;
+
+ int samplerate;
+ int sim_id;
+} audio_modem_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 {
+ void *platform_data;
+ audio_cb_interface_t cb_intf;
+ audio_session_mgr_t session;
+ audio_device_mgr_t device;
+ audio_stream_mgr_t stream;
+ audio_ucm_mgr_t ucm;
+ audio_mixer_mgr_t mixer;
+ audio_modem_mgr_t modem;
+ audio_modem_t *cp;
+ cp_type_t cp_type;
+} audio_mgr_t;
+
+/* Voice */
+typedef enum {
+ VBC_CMD_NONE = 0,
+ /* current mode and volume gain parameters.*/
+ VBC_CMD_SET_MODE = 1,
+ VBC_CMD_RESP_MODE = 2,
+
+ VBC_CMD_SET_GAIN = 3,
+ VBC_CMD_RESP_GAIN = 4,
+
+ /* whether switch vb control to dsp parameters.*/
+ VBC_CMD_SWITCH_CTRL = 5,
+ VBC_CMD_RESP_SWITCH = 6,
+
+ /* whether mute or not.*/
+ VBC_CMD_SET_MUTE = 7,
+ VBC_CMD_RESP_MUTE = 8,
+
+ /* open/close device parameters.*/
+ VBC_CMD_DEVICE_CTRL = 9,
+ VBC_CMD_RESP_DEVICE = 10,
+
+ VBC_CMD_PCM_OPEN = 11,
+ VBC_CMD_RESP_OPEN =12,
+
+ VBC_CMD_PCM_CLOSE = 13,
+ VBC_CMD_RESP_CLOSE = 14,
+
+ VBC_CMD_SET_SAMPLERATE = 15,
+ VBC_CMD_RESP_SAMPLERATE = 16,
+
+ VBC_CMD_MAX
+}vbc_command;
+
+typedef struct {
+ unsigned int sim_card; /*sim card number*/
+} open_pcm_t;
+
+typedef struct _vbc_parameters_head {
+ char tag[4];
+ unsigned int cmd_type;
+ unsigned int paras_size;
+} vbc_parameters_head;
+
+typedef struct {
+ unsigned int is_switch; /* switch vbc contrl to dsp.*/
+} switch_ctrl_t;
+
+typedef struct vbc_control_params {
+ int vbchannel_id;
+ audio_mgr_t *am;
+} vbc_control_params_t;
+
+typedef struct samplerate_ctrl {
+ unsigned int samplerate; /* change samplerate.*/
+} set_samplerate_t;
+
+audio_return_t _audio_stream_init (audio_mgr_t *am);
+audio_return_t _audio_stream_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);
+#ifdef USE_FMRADIO_V4L2_SPRD
+audio_return_t _set_volume_level_fmradio(audio_mgr_t *am, uint32_t level);
+audio_return_t _fmradio_pcm_open (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+audio_return_t _fmradio_pcm_close (audio_mgr_t *am);
+#endif
+audio_return_t _set_route_voicecall (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+void _load_n_open_device_from_ucm (audio_mgr_t *am, const char *verb, int load_only);
+#define _load_device_from_ucm(am, verb) _load_n_open_device_from_ucm(am, verb, 1)
+#define _open_device_from_ucm(am, verb) _load_n_open_device_from_ucm(am, verb, 0)
+void _close_n_unload_device_from_ucm (audio_mgr_t *am, const char *verb, int force_unload);
+#define _close_device_from_ucm(am, verb) _close_n_unload_device_from_ucm(am, verb, 0)
+#define _unload_device_from_ucm(am, verb) _close_n_unload_device_from_ucm(am, verb, 1)
+void _open_virtual_device (audio_mgr_t *am);
+audio_return_t _reset_route (audio_mgr_t *am, int need_inactive);
+
+audio_return_t _audio_session_init (audio_mgr_t *am);
+audio_return_t _audio_session_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[]);
+int _audio_ucm_fill_device_info_list (audio_mgr_t *am, audio_device_info_t *device_info_list, const char *verb);
+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_modem_init (audio_mgr_t *am);
+audio_return_t _audio_modem_deinit (audio_mgr_t *am);
+int i2s_pin_mux_sel (audio_mgr_t *am, int type);
+int _audio_modem_is_call_connected (audio_mgr_t *am);
+int _voice_pcm_open(audio_mgr_t *am);
+int _voice_pcm_close(audio_mgr_t *am, int reset);
+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, uint32_t start_threshold, uint32_t rate);
+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);
+#endif
diff --git a/tizen-audio-modem.c b/tizen-audio-modem.c
new file mode 100644
index 0000000..4d03257
--- /dev/null
+++ b/tizen-audio-modem.c
@@ -0,0 +1,1073 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *
+ * 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 <expat.h>
+#include <stdbool.h>
+#include <vconf.h>
+
+#include "tizen-audio-internal.h"
+
+static int __read_nonblock (int fd, void *buf, int bytes)
+{
+ int ret = 0;
+ int bytes_to_read = bytes;
+
+ if ((fd > 0) && (buf != NULL)) {
+ do {
+ ret = read(fd, buf, bytes);
+ if ( ret > 0) {
+ if (ret <= bytes) {
+ bytes -= ret;
+ }
+ } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
+ break;
+ }
+ } while(bytes);
+ }
+
+ if (bytes == bytes_to_read)
+ return ret ;
+ else
+ return (bytes_to_read - bytes);
+}
+
+static int __write_nonblock (int fd, void *buf, int bytes)
+{
+ int ret = -1;
+ int bytes_to_write = bytes;
+
+ if ((fd > 0) && (buf != NULL)) {
+ do {
+ ret = write(fd, buf, bytes);
+ if ( ret > 0) {
+ if (ret <= bytes) {
+ bytes -= ret;
+ }
+ } else if ((!((errno == EAGAIN) || (errno == EINTR))) || (0 == ret)) {
+ break;
+ }
+ } while(bytes);
+ }
+
+ if (bytes == bytes_to_write)
+ return ret ;
+ else
+ return (bytes_to_write - bytes);
+
+}
+
+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;
+ }
+ if(am->modem.samplerate > 0) {
+ err = snd_pcm_hw_params_set_rate(pcm, params, am->modem.samplerate, 0);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
+ }
+ } else {
+ err = snd_pcm_hw_params_set_rate(pcm, params, (am->device.route_flag & AUDIO_ROUTE_FLAG_NETWORK_WB) ? 16000 : 8000, 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 _audio_modem_is_call_connected (audio_mgr_t *am)
+{
+ int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
+
+ _audio_mixer_control_get_value(am, MIXER_VBC_SWITCH, &val);
+
+ return (val == VBC_TD_CHANNELID) ? 1 : 0;
+}
+
+int _voice_pcm_open (audio_mgr_t *am)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int ret = 0;
+
+ AUDIO_LOG_INFO("open voice pcm handles");
+
+ /* Get playback voice-pcm from ucm conf. Open and set-params */
+ if ((audio_ret = audio_alsa_pcm_open((void *)am, (void **)&am->modem.vbc.voice_pcm_handle_p, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %x", VOICE_PCM_DEVICE, audio_ret);
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(am, am->modem.vbc.voice_pcm_handle_p);
+
+ 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 ((audio_ret = audio_alsa_pcm_open((void *)am, (void **)&am->modem.vbc.voice_pcm_handle_c, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %x", VOICE_PCM_DEVICE, audio_ret);
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(am, am->modem.vbc.voice_pcm_handle_c);
+
+ AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
+
+ return ret;
+}
+
+int _voice_pcm_close (audio_mgr_t *am,int reset)
+{
+ AUDIO_LOG_INFO("close voice pcm handles");
+
+ if (am->modem.vbc.voice_pcm_handle_p) {
+ audio_alsa_pcm_close((void *)am, am->modem.vbc.voice_pcm_handle_p);
+ am->modem.vbc.voice_pcm_handle_p = NULL;
+ AUDIO_LOG_INFO("pcm playback device close");
+ }
+
+ if (am->modem.vbc.voice_pcm_handle_c) {
+ audio_alsa_pcm_close((void *)am, am->modem.vbc.voice_pcm_handle_c);
+ am->modem.vbc.voice_pcm_handle_c = NULL;
+ AUDIO_LOG_INFO("pcm capture device close");
+ }
+ if (reset)
+ _reset_route(am, 1);
+
+ return 0;
+}
+static int __voice_read_samplerate (int fd, set_samplerate_t *paras_ptr)
+{
+ int ret = 0;
+ if (fd > 0 && paras_ptr != NULL) {
+ ret = __read_nonblock(fd, paras_ptr, sizeof(set_samplerate_t));
+ if (ret != sizeof(set_samplerate_t))
+ ret = -1;
+ }
+ AUDIO_LOG_INFO("Return value of read sample rate = %d", ret);
+ return ret;
+
+}
+
+static int __voice_get_samplerate (audio_mgr_t *am,int fd)
+{
+ set_samplerate_t samplerate_paras;
+
+ memset(&samplerate_paras, 0, sizeof(set_samplerate_t));
+ __voice_read_samplerate(fd, &samplerate_paras);
+
+ if (samplerate_paras.samplerate <= 0){
+ am->modem.samplerate = 8000;
+ } else {
+ am->modem.samplerate = samplerate_paras.samplerate;
+ }
+
+ return 0;
+}
+
+static int __vbc_write_response (int fd, unsigned int cmd, uint32_t paras_size)
+{
+ int ret = 0;
+ vbc_parameters_head write_head;
+
+ memset(&write_head, 0, sizeof(vbc_parameters_head));
+ memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+ write_head.cmd_type = cmd + 1;
+ write_head.paras_size = paras_size;
+
+ ret = __write_nonblock(fd, (void*)&write_head, sizeof(vbc_parameters_head));
+ if (ret < 0)
+ AUDIO_LOG_ERROR("write failed");
+
+ return 0;
+}
+
+int i2s_pin_mux_sel (audio_mgr_t *am, int type)
+{
+ int count = 0, ret = 0;
+ audio_modem_t *modem;
+
+ if (!am) {
+ AUDIO_LOG_INFO("i2s_pin_mux_sel am is null");
+ return 0;
+ }
+
+ AUDIO_LOG_INFO("i2s_pin_mux_sel in type is %d",type);
+ modem = am->cp;
+
+ if (type == FM_IIS) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ return 0;
+ }
+ if (type == 0) {
+ if(am->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+ if(modem->i2s_bt.is_ext) {
+ if(modem->i2s_bt.is_switch) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ } else {
+ if(modem->i2s_bt.is_switch) {
+ int value = 0;
+ audio_mixer_control_get_value (am, PIN_SWITCH_IIS0_SYS_SEL, &value);
+ if(value == PIN_SWITCH_IIS0_CP0_ID) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ }
+ if(am->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+ if(modem->i2s_bt.is_switch) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ }
+ }
+ }
+ } else if (type == 1) {
+ if(am->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+ if(modem->i2s_bt.is_ext) {
+ if(modem->i2s_bt.is_switch) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ } else {
+ if(modem->i2s_bt.is_switch) {
+ int value = 0;
+ audio_mixer_control_get_value (am, PIN_SWITCH_IIS0_SYS_SEL, &value);
+ if(value == PIN_SWITCH_IIS0_CP1_ID) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ }
+ if(am->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
+ if(modem->i2s_bt.is_switch) {
+ ret = _audio_mixer_control_set_value(am,
+ PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
+ if (ret == AUDIO_RET_USE_HW_CONTROL)
+ count = 1;
+ }
+ }
+ }
+ }
+ } else {
+ return 0;
+ }
+ return (count==1);
+}
+static void *__vbc_control_thread_run (void *args)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ vbc_parameters_head read_head;
+ vbc_parameters_head write_head;
+ int exit_thread = 0; /* make exit variable global if required to gracefully exit */
+ int vbpipe_fd;
+ vbc_control_params_t *params = (vbc_control_params_t*)args;
+ if (params == NULL) {
+ return (void*)AUDIO_ERR_PARAMETER;
+ }
+ audio_mgr_t *am = params->am;
+ fd_set fds_read;
+ struct timeval timeout = {5,0};
+
+ memset(&read_head, 0, sizeof(vbc_parameters_head));
+ memset(&write_head, 0, sizeof(vbc_parameters_head));
+
+ memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+ write_head.cmd_type = VBC_CMD_NONE;
+ write_head.paras_size = 0;
+
+ AUDIO_LOG_INFO("[voice] vbc control thread run");
+
+again:
+ /* open vbpipe device for vb parameter interface between ap and cp */
+ vbpipe_fd = open(VBPIPE_DEVICE, O_RDWR);
+ if (vbpipe_fd < 0) {
+ if (errno == EINTR)
+ goto again;
+ AUDIO_LOG_ERROR("[voice] vbpipe open failed: %s", strerror(errno));
+ return (void*)AUDIO_ERR_IOCTL;
+ }
+ am->modem.vbc.vbpipe_fd = vbpipe_fd;
+
+ if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
+ AUDIO_LOG_DEBUG("[voice] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
+ }
+
+ AUDIO_LOG_INFO("[voice] %s opened. vbc start loop", VBPIPE_DEVICE);
+
+ /* start loop */
+ while (!exit_thread) {
+ int ret;
+ timeout.tv_sec = 5;;
+ timeout.tv_usec = 0;
+
+ /* read command received from cp */
+
+ FD_ZERO(&fds_read);
+ FD_SET(vbpipe_fd, &fds_read);
+
+ ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
+ if (ret < 0) {
+ ALOGE("voice:select error %d", errno);
+ continue;
+ }
+
+ ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
+ if (ret < 0) {
+ continue;
+ }
+
+ AUDIO_LOG_DEBUG("[voice] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
+
+ if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
+ switch (read_head.cmd_type) {
+ case VBC_CMD_PCM_OPEN: {
+ open_pcm_t open_pcm_params;
+ uint32_t paras_size = ((am->cp->i2s_bt.is_switch << 8) | (am->cp->i2s_bt.index << 0)
+ | (am->cp->i2s_extspk.is_switch << 9) | (am->cp->i2s_extspk.index << 4));
+
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
+
+ /* close all pcm */
+ if (am->cb_intf.close_all_devices) {
+ am->cb_intf.close_all_devices(am->platform_data);
+ }
+
+ /* set Voice verb only when modem is enabled */
+ audio_ret = _set_route_voicecall(am, am->device.active_in, am->device.active_out, am->device.route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
+ }
+
+ /* open pcm for voice call */
+ ret = _voice_pcm_open(am);
+ if (ret < 0) {
+ _voice_pcm_close(am, 1);
+ break;
+ }
+
+ memset(&open_pcm_params, 0, sizeof(open_pcm_t));
+ ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
+ if (ret < 0)
+ AUDIO_LOG_ERROR("read failed");
+ else
+ am->modem.sim_id = open_pcm_params.sim_card;
+
+ if (am->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+ if (am->cp_type == CP_TG)
+ i2s_pin_mux_sel(am, 1);
+ else if(am->cp_type == CP_W)
+ i2s_pin_mux_sel(am, 0);
+ }
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
+ break;
+ }
+
+ case VBC_CMD_PCM_CLOSE: {
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_CLOSE");
+
+ am->modem.samplerate = 0;
+
+ /* close all pcm */
+ if (am->cb_intf.close_all_devices) {
+ am->cb_intf.close_all_devices(am->platform_data);
+ }
+
+ /* close device */
+ _voice_pcm_close(am, 1);
+
+ _audio_mixer_control_set_value(am, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
+
+ /* open pcm of default device */
+ _open_device_from_ucm(am, NULL);
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+ break;
+ }
+
+ case VBC_CMD_RESP_CLOSE: {
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_RESP_CLOSE & send response");
+ ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+ break;
+ }
+
+ case VBC_CMD_SET_MODE: {
+ char dummy[52];
+ memset(dummy, 0, sizeof(dummy));
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MODE");
+
+ if (am->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+ if (am->cp_type == CP_TG)
+ i2s_pin_mux_sel(am, 1);
+ else if(am->cp_type == CP_W)
+ i2s_pin_mux_sel(am, 0);
+ }
+ /* To do: set mode params : __vbc_set_mode_params(am, vbpipe_fd); */
+
+ __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_MODE");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
+ break;
+ }
+ case VBC_CMD_SET_GAIN: {
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_GAIN");
+
+ /* To do: set gain params : __vbc_set_gain_params(am, vbpipe_fd); */
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
+ break;
+ }
+ case VBC_CMD_SWITCH_CTRL: {
+ switch_ctrl_t switch_ctrl_params;
+
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_SWITCH_CTRL");
+
+ memset(&switch_ctrl_params,0,sizeof(switch_ctrl_t));
+ ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
+ if (ret < 0)
+ AUDIO_LOG_ERROR("read failed");
+ else
+ AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
+
+ _audio_mixer_control_set_value(am, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+
+ /* open pcm for virtual device */
+ _open_virtual_device(am);
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
+ break;
+ }
+ case VBC_CMD_SET_MUTE: {
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_MUTE");
+ break;
+ }
+ case VBC_CMD_DEVICE_CTRL: {
+ char dummy[64];
+ memset(dummy, 0, sizeof(dummy));
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_DEVICE_CTRL");
+
+ /* To do: set device ctrl params :__vbc_set_device_ctrl_params(am, vbpipe_fd); */
+ __read_nonblock(vbpipe_fd, dummy, sizeof(dummy));
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_DEVICE_CTRL");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
+
+ break;
+ }
+ case VBC_CMD_SET_SAMPLERATE: {
+ AUDIO_LOG_INFO("[voice] Received VBC_CMD_SET_SAMPLERATE");
+
+ _voice_pcm_close(am, 0);
+
+ __voice_get_samplerate(am, vbpipe_fd);
+
+ ret = _voice_pcm_open(am);
+ if (ret < 0) {
+ _voice_pcm_close(am, 1);
+ break;
+ }
+
+ AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_SAMPLERATE");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
+ break;
+ }
+ default:
+ AUDIO_LOG_WARN("[voice] Unknown command received : %d", read_head.cmd_type);
+ break;
+ }
+ }
+ }
+ if (params)
+ free(params);
+
+ close(vbpipe_fd);
+
+ AUDIO_LOG_INFO("[voice] Exit vbc thread");
+
+ return (void*)0;
+}
+
+static void *__vbc_control_voip_thread_run (void *args)
+{
+ open_pcm_t open_pcm_params;
+ vbc_parameters_head read_head;
+ vbc_parameters_head write_head;
+ int exit_thread = 0; /* make exit variable global if required to gracefully exit */
+ int vbpipe_fd;
+ vbc_control_params_t *params = (vbc_control_params_t*)args;
+ if (params == NULL) {
+ return (void*)AUDIO_ERR_PARAMETER;
+ }
+ audio_mgr_t *am = params->am;
+ fd_set fds_read;
+
+ struct timeval timeout = {5,0};
+
+ memset(&read_head, 0, sizeof(vbc_parameters_head));
+ memset(&write_head, 0, sizeof(vbc_parameters_head));
+
+ memcpy(&write_head.tag[0], VBC_CMD_TAG, 3);
+ write_head.cmd_type = VBC_CMD_NONE;
+ write_head.paras_size = 0;
+
+ AUDIO_LOG_INFO("[voip] vbc control VOIP thread run");
+
+again:
+ /* open vbpipe device for vb parameter interface between ap and cp */
+ vbpipe_fd = open(VBPIPE_VOIP_DEVICE, O_RDWR);
+ if (vbpipe_fd < 0) {
+ if (errno == EINTR)
+ goto again;
+ AUDIO_LOG_ERROR("[voip] vbpipe open failed: %s", strerror(errno));
+ return (void*)0;
+ }
+ am->modem.vbc.vbpipe_voip_fd = vbpipe_fd;
+
+ if (fcntl(vbpipe_fd, F_SETFL, O_NONBLOCK) < 0) {
+ AUDIO_LOG_DEBUG("[voip] vbpipe_fd(%d) fcntl error.", vbpipe_fd);
+ }
+
+ AUDIO_LOG_INFO("[voip] %s opened. vbc start loop", VBPIPE_DEVICE);
+
+ /* start loop */
+ while (!exit_thread) {
+ int ret;
+ timeout.tv_sec = 5;;
+ timeout.tv_usec = 0;
+
+ /* read command received from cp */
+
+ FD_ZERO(&fds_read);
+ FD_SET(vbpipe_fd, &fds_read);
+
+ ret = select(vbpipe_fd+1, &fds_read, NULL, NULL, &timeout);
+ if (ret < 0) {
+ ALOGE("[voip] select error %d", errno);
+ continue;
+ }
+
+ ret = __read_nonblock(vbpipe_fd, &read_head, sizeof(vbc_parameters_head));
+ if (ret < 0) {
+ continue;
+ }
+
+ AUDIO_LOG_DEBUG("[voip] Received %d bytes. data: %s, cmd_type: %d", ret, read_head.tag, read_head.cmd_type);
+
+ if (!memcmp(&read_head.tag[0], VBC_CMD_TAG, 3)) {
+ switch (read_head.cmd_type) {
+ case VBC_CMD_PCM_OPEN: {
+ uint32_t paras_size = ((am->cp->i2s_bt.is_switch << 8) | (am->cp->i2s_bt.index << 0)
+ | (am->cp->i2s_extspk.is_switch << 9) | (am->cp->i2s_extspk.index << 4));
+
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_OPEN");
+
+ memset(&open_pcm_params, 0, sizeof(open_pcm_t));
+ ret = __read_nonblock(vbpipe_fd, &open_pcm_params, sizeof(open_pcm_t));
+ if (ret < 0)
+ AUDIO_LOG_ERROR("read failed");
+
+ AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_PCM_OPEN");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_OPEN, paras_size);
+ break;
+ }
+ case VBC_CMD_PCM_CLOSE: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_PCM_CLOSE & send response");
+
+ __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+
+ break;
+ }
+ case VBC_CMD_RESP_CLOSE: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_RESP_CLOSE & send response");
+
+ ret = __vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
+ break;
+ }
+ case VBC_CMD_SET_MODE: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MODE");
+
+ if (am->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+ if (am->cp_type == CP_TG)
+ i2s_pin_mux_sel(am, 1);
+ else if(am->cp_type == CP_W)
+ i2s_pin_mux_sel(am, 0);
+ }
+ /* To do: set mode params : __vbc_set_mode_params(am, vbpipe_fd); */
+ AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MODE, 0);
+ break;
+ }
+ case VBC_CMD_SET_GAIN: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_GAIN");
+
+ /* To do: set gain params : __vbc_set_gain_params(am, vbpipe_fd); */
+ AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_GAIN");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_GAIN, 0);
+ break;
+ }
+ case VBC_CMD_SWITCH_CTRL: {
+ switch_ctrl_t switch_ctrl_params;
+
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_SWITCH_CTRL");
+
+ memset(&switch_ctrl_params, 0, sizeof(switch_ctrl_t));
+ ret = __read_nonblock(vbpipe_fd, &switch_ctrl_params, sizeof(switch_ctrl_t));
+ if (ret < 0)
+ AUDIO_LOG_ERROR("read failed");
+ else
+ AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
+
+ _audio_mixer_control_set_value(am, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+
+ AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SWITCH_CTRL");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
+ break;
+ }
+ case VBC_CMD_SET_MUTE: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_MUTE & send response");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_MUTE, 0);
+ break;
+ }
+ case VBC_CMD_DEVICE_CTRL: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_DEVICE_CTRL");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_DEVICE_CTRL, 0);
+ break;
+ }
+ case VBC_CMD_SET_SAMPLERATE: {
+ AUDIO_LOG_INFO("[voip] Received VBC_CMD_SET_SAMPLERATE");
+
+ _voice_pcm_close(am, 0);
+ __voice_get_samplerate(am, vbpipe_fd);
+
+ ret = _voice_pcm_open(am);
+ if (ret < 0) {
+ _voice_pcm_close(am, 1);
+ break;
+ }
+ AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_SAMPLERATE");
+ __vbc_write_response(vbpipe_fd, VBC_CMD_SET_SAMPLERATE, 0);
+ break;
+ }
+ default:
+ AUDIO_LOG_WARN("Unknown command received : %d", read_head.cmd_type);
+ break;
+ }
+ }
+ }
+ close(vbpipe_fd);
+ if (params)
+ free(params);
+
+ AUDIO_LOG_INFO("Exit vbc VOIP thread");
+
+ return (void*)0;
+}
+
+static audio_return_t __vbc_control_open (audio_mgr_t *am)
+{
+ vbc_control_params_t *params = (vbc_control_params_t*)malloc(sizeof(vbc_control_params_t));
+ audio_return_t ret = AUDIO_RET_OK;
+ audio_return_t ret2 = AUDIO_RET_OK;
+
+ if (params == NULL) {
+ AUDIO_LOG_ERROR("vbc control param allocation failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ params->am = am;
+ AUDIO_LOG_INFO("vbc control thread create");
+ ret = vbc_thread_new(&am->modem.vbc.thread_handle, NULL, __vbc_control_thread_run, (void*)params);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("vbc control thread create failed");
+ ret = AUDIO_ERR_RESOURCE;
+ return ret;
+ }
+
+ ret2 = vbc_thread_new(&am->modem.vbc.voip_thread_handle, NULL, __vbc_control_voip_thread_run, (void*)params);
+ if (ret2 < 0) {
+ AUDIO_LOG_ERROR("vbc control VOIP thread create failed");
+ ret2 = AUDIO_ERR_RESOURCE;
+ return ret2;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+static audio_return_t __vbc_control_close (audio_mgr_t *am)
+{
+ /* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
+ am->modem.vbc.exit_vbc_thread = 1;
+ close(am->modem.vbc.vbpipe_fd);
+
+ pthread_cancel(am->modem.vbc.thread_handle);
+ pthread_cancel(am->modem.vbc.voip_thread_handle);
+
+ return AUDIO_RET_OK;
+}
+
+static vbc_ctrl_pipe_para_t *__audio_modem_create (audio_modem_t *modem, const char *num)
+{
+ if (!atoi((char *)num)) {
+ AUDIO_LOG_ERROR("Unnormal modem num!");
+ return NULL;
+ }
+
+ modem->num = atoi((char *)num);
+ /* check if we need to allocate space for modem profile */
+ if(!modem->vbc_ctrl_pipe_info)
+ {
+ modem->vbc_ctrl_pipe_info = malloc(modem->num *
+ sizeof(vbc_ctrl_pipe_para_t));
+
+ if (modem->vbc_ctrl_pipe_info == NULL) {
+ AUDIO_LOG_ERROR("Unable to allocate modem profiles");
+ return NULL;
+ }
+ else
+ {
+ /* initialise the new profile */
+ memset((void*)modem->vbc_ctrl_pipe_info, 0x00, modem->num *
+ sizeof(vbc_ctrl_pipe_para_t));
+ }
+ }
+
+ AUDIO_LOG_DEBUG("peter: modem num is %d",modem->num);
+ /* return the profile just added */
+ return modem->vbc_ctrl_pipe_info;
+}
+
+
+static void __audio_modem_start_tag (void *data, const XML_Char *tag_name,
+ const XML_Char **attr)
+{
+ struct modem_config_parse_state *state = data;
+ audio_modem_t *modem = state->modem_info;
+
+ /* Look at tags */
+ if (strcmp(tag_name, "audio") == 0) {
+ if (strcmp(attr[0], "device") == 0) {
+ AUDIO_LOG_INFO("The device name is %s", attr[1]);
+ } else {
+ AUDIO_LOG_ERROR("Unnamed audio!");
+ }
+ } else if (strcmp(tag_name, "modem") == 0) {
+ /* Obtain the modem num */
+ if (strcmp(attr[0], "num") == 0) {
+ AUDIO_LOG_DEBUG("The modem num is '%s'", attr[1]);
+ state->vbc_ctrl_pipe_info = __audio_modem_create(modem, attr[1]);
+ } else {
+ AUDIO_LOG_ERROR("no modem num!");
+ }
+ } else if (strcmp(tag_name, "cp") == 0) {
+ if (state->vbc_ctrl_pipe_info) {
+ /* Obtain the modem name \pipe\vbc filed */
+ if (strcmp(attr[0], "name") != 0) {
+ AUDIO_LOG_ERROR("Unnamed modem!");
+ goto attr_err;
+ }
+ if (strcmp(attr[2], "pipe") != 0) {
+ AUDIO_LOG_ERROR("'%s' No pipe filed!", attr[0]);
+ goto attr_err;
+ }
+ if (strcmp(attr[4], "vbchannel") != 0) {
+ AUDIO_LOG_ERROR("'%s' No vbc filed!", attr[0]);
+ goto attr_err;
+ }
+ AUDIO_LOG_DEBUG("cp name is '%s', pipe is '%s',vbc is '%s'", attr[1], attr[3],attr[5]);
+ if(strcmp(attr[1], "w") == 0)
+ {
+ state->vbc_ctrl_pipe_info->cp_type = CP_W;
+ }
+ else if(strcmp(attr[1], "t") == 0)
+ {
+ state->vbc_ctrl_pipe_info->cp_type = CP_TG;
+ }
+ memcpy((void*)state->vbc_ctrl_pipe_info->s_vbc_ctrl_pipe_name,(void*)attr[3],strlen((char *)attr[3]));
+ state->vbc_ctrl_pipe_info->channel_id = atoi((char *)attr[5]);
+ state->vbc_ctrl_pipe_info++;
+
+ } else {
+ AUDIO_LOG_ERROR("error profile!");
+ }
+ } else if (strcmp(tag_name, "i2s_for_btcall") == 0) {
+ if (strcmp(attr[0], "index") == 0) {
+ AUDIO_LOG_DEBUG("The iis_for_btcall index is '%s'", attr[1]);
+ modem->i2s_bt.index = atoi((char *)attr[1]);
+ } else {
+ AUDIO_LOG_ERROR("no iis_ctl index for bt call!");
+ }
+
+ if (strcmp(attr[2], "switch") == 0) {
+ AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
+ if(strcmp(attr[3],"1") == 0)
+ modem->i2s_bt.is_switch = true;
+ else if(strcmp(attr[3],"0") == 0)
+ modem->i2s_bt.is_switch = false;
+ } else {
+ AUDIO_LOG_ERROR("no iis_ctl switch for bt call!");
+ }
+ if (strcmp(attr[4], "dst") == 0) {
+ AUDIO_LOG_DEBUG("The iis_for_btcall dst is '%s'", attr[5]);
+ if (strcmp(attr[5], "internal") == 0)
+ modem->i2s_bt.is_ext = 0;
+ else if (strcmp(attr[5], "external") == 0)
+ modem->i2s_bt.is_ext = 1;
+ } else {
+ AUDIO_LOG_ERROR("no dst path for bt call!");
+ }
+ } else if (strcmp(tag_name, "i2s_for_extspeaker") == 0) {
+ if (strcmp(attr[0], "index") == 0) {
+ AUDIO_LOG_DEBUG("The i2s_for_extspeaker index is '%s'", attr[1]);
+ modem->i2s_extspk.index = atoi((char *)attr[1]);
+ } else {
+ AUDIO_LOG_ERROR("no iis_ctl index for extspk call!");
+ }
+ if (strcmp(attr[2], "switch") == 0) {
+ AUDIO_LOG_DEBUG("The iis_for_btcall switch is '%s'", attr[3]);
+ if(strcmp(attr[3],"1") == 0)
+ modem->i2s_extspk.is_switch = true;
+ else if(strcmp(attr[3],"0") == 0)
+ modem->i2s_extspk.is_switch = false;
+ } else {
+ AUDIO_LOG_ERROR("no iis_ctl switch for extspk call!");
+ }
+ if (strcmp(attr[4], "dst") == 0) {
+ if (strcmp(attr[5], "external") == 0)
+ modem->i2s_extspk.is_ext = 1;
+ else if(strcmp(attr[5], "internal") == 0)
+ modem->i2s_extspk.is_ext = 0;
+
+ AUDIO_LOG_DEBUG("The i2s_for_extspeaker dst is '%d'", modem->i2s_extspk.is_ext);
+
+ } else {
+ AUDIO_LOG_ERROR("no dst path for bt call!");
+ }
+ } else if (strcmp(tag_name, "debug") == 0) { //parse debug info
+ if (strcmp(attr[0], "enable") == 0) {
+ if (strcmp(attr[1], "0") == 0) {
+ modem->debug_info.enable = 0;
+ } else {
+ modem->debug_info.enable = 1;
+ }
+ } else {
+ AUDIO_LOG_ERROR("no adaptable type for debug!");
+ goto attr_err;
+ }
+ } else if (strcmp(tag_name, "debuginfo") == 0) { //parse debug info
+ if (strcmp(attr[0], "sleepdeltatimegate") == 0) {
+ AUDIO_LOG_DEBUG("The sleepdeltatimegate is '%s'", attr[1]);
+ modem->debug_info.sleeptime_gate=atoi((char *)attr[1]);
+ } else if (strcmp(attr[0], "pcmwritetimegate") == 0) {
+ AUDIO_LOG_DEBUG("The pcmwritetimegate is '%s'", attr[1]);
+ modem->debug_info.pcmwritetime_gate=atoi((char *)attr[1]);
+ } else if (strcmp(attr[0], "lastthiswritetimegate") == 0) {
+ AUDIO_LOG_DEBUG("The lastthiswritetimegate is '%s'", attr[1]);
+ modem->debug_info.lastthis_outwritetime_gate=atoi((char *)attr[1]);
+ } else {
+ AUDIO_LOG_ERROR("no adaptable info for debuginfo!");
+ goto attr_err;
+ }
+ }
+
+attr_err:
+ return;
+}
+static void __audio_modem_end_tag (void *data, const XML_Char *tag_name)
+{
+ return;
+}
+
+static audio_modem_t * __audio_modem_parse (void)
+{
+ struct config_parse_state state;
+ XML_Parser parser;
+ FILE *file;
+ int bytes_read;
+ void *buf;
+ audio_modem_t *modem = NULL;
+
+ modem = calloc(1, sizeof(audio_modem_t));
+
+ if(modem == NULL) {
+ goto err_alloc;
+ }
+ memset(modem, 0, sizeof(audio_modem_t));
+ modem->num = 0;
+ modem->vbc_ctrl_pipe_info = NULL;
+
+ file = fopen(AUDIO_XML_PATH, "r");
+ if (!file) {
+ AUDIO_LOG_ERROR("Failed to open %s", AUDIO_XML_PATH);
+ goto err_fopen;
+ }
+
+ parser = XML_ParserCreate(NULL);
+ if (!parser) {
+ AUDIO_LOG_ERROR("Failed to create XML parser");
+ goto err_parser_create;
+ }
+
+ memset(&state, 0, sizeof(state));
+ state.modem_info = modem;
+ XML_SetUserData(parser, &state);
+ XML_SetElementHandler(parser, __audio_modem_start_tag, __audio_modem_end_tag);
+
+ for (;;) {
+ buf = XML_GetBuffer(parser, BUF_SIZE);
+ if (buf == NULL)
+ goto err_parse;
+
+ bytes_read = fread(buf, 1, BUF_SIZE, file);
+ if (bytes_read < 0)
+ goto err_parse;
+
+ if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
+ AUDIO_LOG_ERROR("Error in codec PGA xml (%s)", AUDIO_XML_PATH);
+ goto err_parse;
+ }
+
+ if (bytes_read == 0)
+ break;
+ }
+ XML_ParserFree(parser);
+ fclose(file);
+ return modem;
+
+err_parse:
+ XML_ParserFree(parser);
+err_parser_create:
+ fclose(file);
+err_fopen:
+ free(modem);
+err_alloc:
+ modem = NULL;
+ return NULL;
+}
+audio_return_t _audio_modem_init (audio_mgr_t *am)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ am->modem.vbc.vbpipe_count = 0;
+
+ /* Initialize vbc interface */
+ audio_ret = __vbc_control_open(am);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("__vbc_control_open failed");
+ goto exit;
+ }
+ am->modem.vbc.voice_pcm_handle_p = NULL;
+ am->modem.vbc.voice_pcm_handle_c = NULL;
+ am->modem.samplerate = 0;
+ am->cp = __audio_modem_parse();
+ if (am->cp == NULL) {
+ AUDIO_LOG_ERROR("modem parse failed");
+ goto exit;
+ }
+ am->cp_type = am->cp->vbc_ctrl_pipe_info->cp_type;
+
+ /* This ctrl need to be set "0" always - SPRD */
+ _audio_mixer_control_set_value(am, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
+
+exit:
+ return audio_ret;
+}
+
+audio_return_t _audio_modem_deinit (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ /* Close vbc interface */
+ __vbc_control_close(am);
+
+ return AUDIO_RET_OK;
+}
+
diff --git a/tizen-audio-session.c b/tizen-audio-session.c
new file mode 100644
index 0000000..08ef9aa
--- /dev/null
+++ b/tizen-audio-session.c
@@ -0,0 +1,245 @@
+/*
+ * 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 "tizen-audio-internal.h"
+
+static const char *__get_session_string_by_idx (uint32_t session_idx)
+{
+ switch (session_idx) {
+ case AUDIO_SESSION_MEDIA: return "media";
+ case AUDIO_SESSION_VOICECALL: return "voicecall";
+ case AUDIO_SESSION_VIDEOCALL: return "videocall";
+ case AUDIO_SESSION_VOIP: return "voip";
+ case AUDIO_SESSION_FMRADIO: return "fmradio";
+ case AUDIO_SESSION_CAMCORDER: return "camcorder";
+ case AUDIO_SESSION_NOTIFICATION: return "notification";
+ case AUDIO_SESSION_ALARM: return "alarm";
+ case AUDIO_SESSION_EMERGENCY: return "emergency";
+ case AUDIO_SESSION_VOICE_RECOGNITION: return "voice_recognition";
+ default: return "invalid";
+ }
+}
+
+static const char *__get_subsession_string_by_idx (uint32_t subsession_idx)
+{
+ switch (subsession_idx) {
+ case AUDIO_SUBSESSION_NONE: return "none";
+ case AUDIO_SUBSESSION_VOICE: return "voice";
+ case AUDIO_SUBSESSION_RINGTONE: return "ringtone";
+ case AUDIO_SUBSESSION_MEDIA: return "media";
+ case AUDIO_SUBSESSION_INIT: return "init";
+ case AUDIO_SUBSESSION_VR_NORMAL: return "vr_normal";
+ case AUDIO_SUBSESSION_VR_DRIVE: return "vr_drive";
+ case AUDIO_SUBSESSION_STEREO_REC: return "stereo_rec";
+ case AUDIO_SUBSESSION_MONO_REC: return "mono_rec";
+ default: return "invalid";
+ }
+}
+
+static const char * __get_sessin_cmd_string (uint32_t cmd)
+{
+ switch (cmd) {
+ case AUDIO_SESSION_CMD_START: return "start";
+ case AUDIO_SESSION_CMD_SUBSESSION: return "subsession";
+ case AUDIO_SESSION_CMD_END: return "end";
+ default: return "invalid";
+ }
+}
+
+audio_return_t _audio_session_init (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ am->session.session = AUDIO_SESSION_MEDIA;
+ am->session.subsession = AUDIO_SUBSESSION_NONE;
+ am->session.is_recording = 0;
+ am->session.is_radio_on = 0;
+ am->session.is_call_session = 0;
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_session_deinit (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_set_session (void *userdata, uint32_t session, uint32_t subsession, uint32_t cmd)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ uint32_t prev_subsession = am->session.subsession;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("session %s:%s(%s)->%s(%s)", __get_sessin_cmd_string(cmd),
+ __get_session_string_by_idx(am->session.session), __get_subsession_string_by_idx(am->session.subsession),
+ __get_session_string_by_idx(session), __get_subsession_string_by_idx(subsession));
+
+ if (cmd == AUDIO_SESSION_CMD_START) {
+ if (am->session.is_call_session) {
+ AUDIO_LOG_ERROR("call active its not possible to have any other session start now");
+ return audio_ret;
+ }
+ am->session.session = session;
+ am->session.subsession = subsession;
+
+ if (session == AUDIO_SESSION_FMRADIO) {
+#ifdef USE_FMRADIO_V4L2_SPRD
+ int media_volume = 0;
+#endif
+ am->session.is_radio_on = 1;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ _fmradio_pcm_open(am, am->device.active_in, am->device.active_out, 0);
+#endif
+ audio_set_route(userdata, session, subsession, am->device.active_in, am->device.active_out, 0);
+#ifdef USE_FMRADIO_V4L2_SPRD
+ audio_get_volume_level(am, AUDIO_VOLUME_TYPE_MEDIA, &media_volume);
+ _set_volume_level_fmradio(am, media_volume);
+ i2s_pin_mux_sel(am, FM_IIS);
+
+ /* change source due to limitation of FM recording */
+ _unload_device_from_ucm(am, NULL);
+ _load_device_from_ucm(am, NULL);
+#endif
+ }
+
+ if ((session == AUDIO_SESSION_VIDEOCALL) ||
+ (session == AUDIO_SESSION_VOICECALL) ||
+ (session == AUDIO_SESSION_VOIP)) {
+ AUDIO_LOG_INFO("set call session");
+ am->session.is_call_session = 1;
+ }
+
+ } else if (cmd == AUDIO_SESSION_CMD_END) {
+
+ if ((session == AUDIO_SESSION_VIDEOCALL) ||
+ (session == AUDIO_SESSION_VOICECALL) ||
+ (session == AUDIO_SESSION_VOIP)) {
+ AUDIO_LOG_INFO("unset call session");
+ am->session.is_call_session = 0;
+ }
+
+ if (am->session.is_call_session) {
+ AUDIO_LOG_ERROR("call active its not possible to have any other session end now");
+ return audio_ret;
+ }
+
+ if (session == AUDIO_SESSION_VIDEOCALL && _audio_modem_is_call_connected(am)) {
+ _unload_device_from_ucm(am, NULL);
+
+ /* close all pcm */
+ if (am->cb_intf.close_all_devices) {
+ am->cb_intf.close_all_devices(am->platform_data);
+ }
+
+ _audio_mixer_control_set_value(am, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
+
+ /* close device */
+ _voice_pcm_close(am, 1);
+
+ /* open pcm of default device */
+ _open_device_from_ucm(am, NULL);
+ }
+ if (session == AUDIO_SESSION_MEDIA && (prev_subsession == AUDIO_SUBSESSION_STEREO_REC || AUDIO_SUBSESSION_MONO_REC)) {
+ am->session.is_recording = 0;
+ }
+ if (session != AUDIO_SESSION_FMRADIO && am->session.is_radio_on) {
+ am->session.session = AUDIO_SESSION_FMRADIO;
+ } else {
+ am->session.session = AUDIO_SESSION_MEDIA;
+ }
+ am->session.subsession = AUDIO_SUBSESSION_NONE;
+
+ if (session == AUDIO_SESSION_FMRADIO) {
+ am->session.is_radio_on = 0;
+#ifdef USE_FMRADIO_V4L2_SPRD
+ _fmradio_pcm_close(am);
+#endif
+ audio_ret = _reset_route(am, 0);
+ if (audio_ret != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("_reset_route failed with %d", audio_ret);
+ }
+#ifdef USE_FMRADIO_V4L2_SPRD
+ /* change source due to limitation of FM recording */
+ _unload_device_from_ucm(am, NULL);
+ _open_device_from_ucm(am, NULL);
+#endif
+ }
+ } else if (cmd == AUDIO_SESSION_CMD_SUBSESSION) {
+
+ if (am->session.is_call_session) {
+ if ((subsession != AUDIO_SUBSESSION_VOICE) &&
+ (subsession != AUDIO_SUBSESSION_MEDIA) &&
+ (subsession != AUDIO_SUBSESSION_RINGTONE)) {
+ AUDIO_LOG_ERROR("call active we can only have one of AUDIO_SUBSESSION_VOICE AUDIO_SUBSESSION_MEDIA AUDIO_SUBSESSION_RINGTONE as a sub-session");
+ return audio_ret;
+ }
+ }
+
+ am->session.subsession = subsession;
+
+ if (prev_subsession != subsession && am->session.session == AUDIO_SESSION_VIDEOCALL && subsession == AUDIO_SUBSESSION_VOICE) {
+ /* close all pcm */
+ if (am->cb_intf.close_all_devices) {
+ am->cb_intf.close_all_devices(am->platform_data);
+ }
+ if (am->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
+ if (am->cp_type == CP_TG)
+ i2s_pin_mux_sel(am, 1);
+ else if(am->cp_type == CP_W)
+ i2s_pin_mux_sel(am, 0);
+ }
+
+ audio_ret = _set_route_videocall(am, am->device.active_in, am->device.active_out, am->device.route_flag);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_WARN("set videocall route return 0x%x", audio_ret);
+ }
+
+ if (_voice_pcm_open(am) < 0) {
+ _voice_pcm_close(am, 1);
+ return AUDIO_ERR_RESOURCE;
+ }
+ _open_device_from_ucm(am, NULL);
+ }
+
+ if (prev_subsession != subsession && subsession == AUDIO_SUBSESSION_VOICE) {
+ am->session.is_radio_on = 0;
+ am->session.is_recording = 0;
+ }
+
+ if (subsession == AUDIO_SUBSESSION_STEREO_REC || subsession == AUDIO_SUBSESSION_MONO_REC) {
+ am->session.is_recording = 1;
+ } else if (am->session.is_recording == 1 && subsession == AUDIO_SUBSESSION_INIT) {
+ am->session.is_recording = 0;
+ }
+ }
+
+ return audio_ret;
+}
diff --git a/tizen-audio-stream.c b/tizen-audio-stream.c
new file mode 100644
index 0000000..8ddbbad
--- /dev/null
+++ b/tizen-audio-stream.c
@@ -0,0 +1,638 @@
+/*
+ * 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)
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+#define RADIO_TUNING_DEFUALT_FILE "/usr/etc/mmfw_fmradio.ini"
+#define RADIO_TUNING_TEMP_FILE "/opt/usr/media/.mmfw_fmradio.ini"
+#define RADIO_TUNING_ENABLE "tuning:enable"
+#define RADIO_TUNING_VOLUME_LEVELS "fmradio:volume_levels"
+#define RADIO_TUNING_VOLUME_TABLE "fmradio:volume_table"
+#endif
+
+enum {
+ STREAM_DEVICE_SPEAKER,
+ STREAM_DEVICE_HEADSET,
+ STREAM_DEVICE_BLUETOOTH,
+ STREAM_DEVICE_HDMI,
+ STREAM_DEVICE_DOCK,
+ STREAM_DEVICE_MAX,
+};
+
+static const char *g_volume_vconf[AUDIO_VOLUME_TYPE_VCONF_MAX] = {
+ "file/private/sound/volume/system", /* AUDIO_VOLUME_TYPE_SYSTEM */
+ "file/private/sound/volume/notification", /* AUDIO_VOLUME_TYPE_NOTIFICATION */
+ "file/private/sound/volume/alarm", /* AUDIO_VOLUME_TYPE_ALARM */
+ "file/private/sound/volume/ringtone", /* AUDIO_VOLUME_TYPE_RINGTONE */
+ "file/private/sound/volume/media", /* AUDIO_VOLUME_TYPE_MEDIA */
+ "file/private/sound/volume/call", /* AUDIO_VOLUME_TYPE_CALL */
+ "file/private/sound/volume/voip", /* AUDIO_VOLUME_TYPE_VOIP */
+ "file/private/sound/volume/voice", /* AUDIO_VOLUME_TYPE_VOICE */
+};
+
+static inline uint8_t __get_volume_dev_index(audio_mgr_t *am, uint32_t volume_type)
+{
+
+ switch (am->device.active_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER: return AUDIO_VOLUME_DEVICE_SPEAKER;
+ case AUDIO_DEVICE_OUT_RECEIVER: return AUDIO_VOLUME_DEVICE_RECEIVER;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY: return AUDIO_VOLUME_DEVICE_EARJACK;
+ case AUDIO_DEVICE_OUT_BT_SCO: return AUDIO_VOLUME_DEVICE_BT_SCO;
+ case AUDIO_DEVICE_OUT_BT_A2DP: return AUDIO_VOLUME_DEVICE_BT_A2DP;
+ case AUDIO_DEVICE_OUT_DOCK: return AUDIO_VOLUME_DEVICE_DOCK;
+ case AUDIO_DEVICE_OUT_HDMI: return AUDIO_VOLUME_DEVICE_HDMI;
+ case AUDIO_DEVICE_OUT_MIRRORING: return AUDIO_VOLUME_DEVICE_MIRRORING;
+ case AUDIO_DEVICE_OUT_USB_AUDIO: return AUDIO_VOLUME_DEVICE_USB;
+ case AUDIO_DEVICE_OUT_MULTIMEDIA_DOCK: return AUDIO_VOLUME_DEVICE_MULTIMEDIA_DOCK;
+ default: return AUDIO_VOLUME_DEVICE_SPEAKER;
+ }
+}
+
+static const uint8_t __get_stream_dev_index (uint32_t device_out)
+{
+ switch (device_out) {
+ case AUDIO_DEVICE_OUT_SPEAKER: return STREAM_DEVICE_SPEAKER;
+ case AUDIO_DEVICE_OUT_RECEIVER: return STREAM_DEVICE_SPEAKER;
+ case AUDIO_DEVICE_OUT_WIRED_ACCESSORY: return STREAM_DEVICE_HEADSET;
+ case AUDIO_DEVICE_OUT_BT_SCO: return STREAM_DEVICE_BLUETOOTH;
+ case AUDIO_DEVICE_OUT_BT_A2DP: return STREAM_DEVICE_BLUETOOTH;
+ case AUDIO_DEVICE_OUT_DOCK: return STREAM_DEVICE_DOCK;
+ case AUDIO_DEVICE_OUT_HDMI: return STREAM_DEVICE_HDMI;
+ case AUDIO_DEVICE_OUT_MIRRORING: return STREAM_DEVICE_SPEAKER;
+ case AUDIO_DEVICE_OUT_USB_AUDIO: return STREAM_DEVICE_SPEAKER;
+ case AUDIO_DEVICE_OUT_MULTIMEDIA_DOCK: return STREAM_DEVICE_DOCK;
+ default:
+ AUDIO_LOG_DEBUG("invalid device_out:%d", device_out);
+ break;
+ }
+
+ return STREAM_DEVICE_SPEAKER;
+}
+
+static const char *__get_device_string_by_idx (uint32_t dev_idx)
+{
+ switch (dev_idx) {
+ case STREAM_DEVICE_SPEAKER: return "speaker";
+ case STREAM_DEVICE_HEADSET: return "headset";
+ case STREAM_DEVICE_BLUETOOTH: return "btheadset";
+ case STREAM_DEVICE_HDMI: return "hdmi";
+ case STREAM_DEVICE_DOCK: return "dock";
+ default: return "invalid";
+ }
+}
+
+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 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";
+ }
+}
+#ifdef USE_FMRADIO_V4L2_SPRD
+audio_return_t _set_volume_level_fmradio(audio_mgr_t *am, uint32_t level)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ int volume = 0;
+ int mute = -1;
+
+ /* Applying mute at volume zero */
+ if (level == 0) {
+ audio_ret = _audio_mixer_control_set_value(am, MIXER_FMRADIO_MUTE, 0);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_MUTE);
+ }
+ } else {
+ audio_ret = _audio_mixer_control_get_value(am, MIXER_FMRADIO_MUTE, &mute);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_MUTE);
+ return audio_ret;
+ }
+ if (mute == 0) {
+ audio_ret = _audio_mixer_control_set_value(am, MIXER_FMRADIO_MUTE, 1);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_MUTE);
+ return audio_ret;
+ }
+ }
+ }
+
+ if (AUDIO_IS_ERROR(_audio_mixer_control_get_value(am, MIXER_FMRADIO_L_VOLUME, &volume))) {
+ AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_L_VOLUME);
+ } else {
+ if (volume != am->stream.fmradio_volume_table[level]) {
+ audio_ret = _audio_mixer_control_set_value(am, MIXER_FMRADIO_L_VOLUME, am->stream.fmradio_volume_table[level]);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_L_VOLUME);
+ return audio_ret;
+ }
+ }
+ }
+
+ if (AUDIO_IS_ERROR(_audio_mixer_control_get_value(am, MIXER_FMRADIO_R_VOLUME, &volume))) {
+ AUDIO_LOG_ERROR("get mixer(%s) failed", MIXER_FMRADIO_R_VOLUME);
+ } else {
+ if (volume != am->stream.fmradio_volume_table[level]) {
+ audio_ret = _audio_mixer_control_set_value(am, MIXER_FMRADIO_R_VOLUME, am->stream.fmradio_volume_table[level]);
+ if (AUDIO_IS_ERROR(audio_ret)) {
+ AUDIO_LOG_ERROR("set mixer(%s) failed", MIXER_FMRADIO_R_VOLUME);
+ }
+ }
+ }
+ return audio_ret;
+}
+#endif
+static void __dump_info(char *dump, audio_info_t *info)
+{
+ int len;
+ char name[64] = { '\0', };
+
+ if (info->device.api == AUDIO_DEVICE_API_ALSA) {
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "device:alsa(%d.%d)", info->device.alsa.card_idx, info->device.alsa.device_idx);
+ } else if (info->device.api == AUDIO_DEVICE_API_ALSA) {
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "device:bluez(%s,nrec:%d)", info->device.bluez.protocol, info->device.bluez.nrec);
+ } else {
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "device:unknown");
+ }
+
+ if (len > 0)
+ dump += len;
+
+ strncpy(name, info->stream.name ? info->stream.name : "null", sizeof(name)-1);
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "stream:%s(%dhz,%dch,vol:%s,gain:%s)",
+ name, info->stream.samplerate, info->stream.channels,
+ __get_volume_type_string_by_idx(info->stream.volume_type), __get_gain_type_string_by_idx(info->stream.gain_type));
+
+ if (len > 0)
+ dump += len;
+
+ *dump = '\0';
+}
+
+static void __dump_tb (audio_mgr_t *am)
+{
+ audio_volume_gain_table_t *volume_gain_table = am->stream.volume_gain_table;
+ uint32_t dev_idx, 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 >>>>>");
+
+
+ for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_VCONF_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_gain_table->volume_level_max[vol_type_idx]; vol_level_idx++) {
+ snprintf(dump_str_ptr, 6, "%01.2f ", volume_gain_table->volume[vol_type_idx][vol_level_idx]);
+ dump_str_ptr += strlen(dump_str_ptr);
+ }
+ AUDIO_LOG_INFO("%s", dump_str);
+ }
+
+
+ /* 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));
+
+ 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_gain_table->gain[gain_type_idx]);
+ dump_str_ptr += strlen(dump_str_ptr);
+ }
+ AUDIO_LOG_INFO("%s", dump_str);
+
+}
+
+static audio_return_t __load_volume_gain_table_from_ini (audio_mgr_t *am)
+{
+ dictionary * dict = NULL;
+ uint32_t vol_type_idx, vol_level_idx, gain_type_idx;
+ audio_volume_gain_table_t *volume_gain_table = am->stream.volume_gain_table;
+ int size = 0;
+ const char delimiter[] = ", ";
+ char *key, *list_str, *token, *ptr = NULL;
+ const char *section = "volumes";
+
+ dict = iniparser_load(VOLUME_INI_TEMP_PATH);
+ if (!dict) {
+ AUDIO_LOG_DEBUG("Use default volume&gain ini file");
+ dict = iniparser_load(VOLUME_INI_DEFAULT_PATH);
+ if (!dict) {
+ AUDIO_LOG_WARN("Loading volume&gain table from ini file failed");
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+
+ /* Load volume table */
+ for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_VCONF_MAX; vol_type_idx++) {
+ const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
+
+ volume_gain_table->volume_level_max[vol_type_idx] = 0;
+ size = strlen(section) + strlen(vol_type_str) + 2;
+ key = malloc(size);
+ if (key) {
+ snprintf(key, size, "%s:%s", section, vol_type_str);
+ list_str = iniparser_getstr(dict, key);
+ 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_gain_table->volume[vol_type_idx][volume_gain_table->volume_level_max[vol_type_idx]++] = vol_value;
+ token = strtok_r(NULL, delimiter, &ptr);
+ }
+ } else {
+ volume_gain_table->volume_level_max[vol_type_idx] = 1;
+ for (vol_level_idx = 0; vol_level_idx < AUDIO_VOLUME_LEVEL_MAX; vol_level_idx++) {
+ volume_gain_table->volume[vol_type_idx][vol_level_idx] = VOLUME_VALUE_MAX;
+ }
+ }
+ free(key);
+ }
+ }
+
+ /* Load gain table */
+ volume_gain_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(section) + strlen("gain") + strlen(gain_type_str) + 3;
+ key = malloc(size);
+ if (key) {
+ snprintf(key, size, "%s:gain_%s", section, gain_type_str);
+ token = iniparser_getstr(dict, key);
+ if (token) {
+ volume_gain_table->gain[gain_type_idx] = atof(token);
+ } else {
+ volume_gain_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
+ }
+ free(key);
+ } else {
+ volume_gain_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
+ }
+ }
+
+ iniparser_freedict(dict);
+
+ __dump_tb(am);
+
+ return AUDIO_RET_OK;
+}
+
+#ifdef USE_FMRADIO_V4L2_SPRD
+int _radio_load_volume_table(int** volume_table, int *number_of_elements)
+{
+ dictionary * dict = NULL;
+ const char delimiter[] = ", ";
+ char* ptr = NULL;
+ char* token = NULL;
+ char* list_str = NULL;
+ int* temp_table = NULL;
+ int index = 0;
+ int ret = 0;
+
+ bool tuning_enable = 0;
+ int not_found = -1;
+ int value = 0;
+
+ dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+ if (dict == NULL) {
+ AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+ return AUDIO_ERR_UNDEFINED;
+ } else {
+ /*tuning enable */
+ value = iniparser_getboolean(dict, RADIO_TUNING_ENABLE, not_found);
+ if (value == not_found) {
+ AUDIO_LOG_ERROR("Can't get Tuning Enable value");
+ } else {
+ tuning_enable = value;
+ AUDIO_LOG_INFO("Tuning enabled.");
+ }
+ iniparser_freedict(dict); /*Cleanup*/
+ }
+
+ if (tuning_enable) {
+ AUDIO_LOG_INFO("Tuning enabled. load temp tuning file.");
+ dict = iniparser_load(RADIO_TUNING_TEMP_FILE);
+ if (!dict) {
+ AUDIO_LOG_WARN("%s load failed. Tuning enabled but there is not tuning temp file. Use temporary file", RADIO_TUNING_TEMP_FILE);
+ dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+ if (!dict) {
+ AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+ } else {
+ AUDIO_LOG_INFO("Tuning diabled. load default tuning file.");
+ dict = iniparser_load(RADIO_TUNING_DEFUALT_FILE);
+ if (!dict) {
+ AUDIO_LOG_ERROR("%s load failed", RADIO_TUNING_DEFUALT_FILE);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+
+ *number_of_elements = iniparser_getint (dict, RADIO_TUNING_VOLUME_LEVELS, -1);
+ if (*number_of_elements == -1) {
+ ret = AUDIO_ERR_UNDEFINED;
+ goto error;
+ }
+ temp_table = (int *)malloc ((*number_of_elements) * sizeof(int));
+ if (!temp_table) {
+ goto error;
+ }
+ *volume_table = temp_table;
+
+ list_str = iniparser_getstr(dict, RADIO_TUNING_VOLUME_TABLE);
+ if (list_str) {
+ token = strtok_r(list_str, delimiter, &ptr);
+ while (token) {
+ temp_table[index] = atoi(token);
+ AUDIO_LOG_INFO("fm volume index %d is %d", index, temp_table[index]);
+ index++;
+ token = strtok_r(NULL, delimiter, &ptr);
+ }
+ }
+error:
+ iniparser_freedict(dict);
+ return ret;
+}
+#endif
+
+audio_return_t _audio_stream_init (audio_mgr_t *am)
+{
+ int i, val;
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int init_value[AUDIO_VOLUME_TYPE_VCONF_MAX] = { 9, 11, 7, 11, 7, 4, 4, 7 };
+#ifdef USE_FMRADIO_V4L2_SPRD
+ int number_of_steps = 0;
+ int index =0;
+ int* fm_table = NULL;
+#endif
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_VCONF_MAX; i++) {
+ am->stream.volume_level[i] = init_value[i];
+ }
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_VCONF_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->stream.volume_level[i] = val;
+ }
+
+ if (!(am->stream.volume_gain_table = malloc(sizeof(audio_volume_gain_table_t)))) {
+ AUDIO_LOG_ERROR("volume_gain_table malloc failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ audio_ret = __load_volume_gain_table_from_ini(am);
+ if(audio_ret != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("gain table load error");
+ return AUDIO_ERR_UNDEFINED;
+ }
+#ifdef USE_FMRADIO_V4L2_SPRD
+ _radio_load_volume_table(&fm_table, &number_of_steps);
+ if (fm_table) {
+ AUDIO_LOG_DEBUG("number of steps -> %d", number_of_steps);
+ /*copy from temp structure to main strcture*/
+ for (index = 0; index < number_of_steps; index++) {
+ am->stream.fmradio_volume_table[index] = fm_table[index];
+ }
+ free(fm_table);
+ fm_table = NULL;
+ }
+
+#endif
+ return audio_ret;
+}
+
+audio_return_t _audio_stream_deinit (audio_mgr_t *am)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ if (am->stream.volume_gain_table) {
+ free(am->stream.volume_gain_table);
+ am->stream.volume_gain_table = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_get_volume_level_max (void *userdata, uint32_t volume_type, uint32_t *level)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_gain_table_t *volume_gain_table;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(am->stream.volume_gain_table, AUDIO_ERR_PARAMETER);
+
+ /* Get max volume level by device & type */
+ volume_gain_table = am->stream.volume_gain_table;
+
+ if (volume_type < AUDIO_VOLUME_TYPE_VCONF_MAX) {
+ *level = volume_gain_table->volume_level_max[volume_type];
+ AUDIO_LOG_DEBUG("get_volume_level_max:%s=>%d", __get_volume_type_string_by_idx(volume_type), *level);
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_get_volume_level (void *userdata, uint32_t volume_type, uint32_t *level)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ if (volume_type < AUDIO_VOLUME_TYPE_VCONF_MAX)
+ *level = am->stream.volume_level[volume_type];
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_get_volume_value (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t level, double *value)
+{
+ if (info) {
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_gain_table_t *volume_gain_table;
+ char dump_str[AUDIO_DUMP_STR_LEN];
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(am->stream.volume_gain_table, AUDIO_ERR_PARAMETER);
+ __dump_info(&dump_str[0], info);
+ /* Get basic volume by device & type & level */
+ volume_gain_table = am->stream.volume_gain_table;
+ if (volume_type < AUDIO_VOLUME_TYPE_VCONF_MAX) {
+ if (volume_gain_table->volume_level_max[volume_type] < level)
+ *value = VOLUME_VALUE_MAX;
+ else
+ *value = volume_gain_table->volume[volume_type][level];
+ *value *= volume_gain_table->gain[info->stream.gain_type];
+ } else if (volume_type == AUDIO_VOLUME_TYPE_FIXED)
+ *value = 1.0 * volume_gain_table->gain[info->stream.gain_type];
+
+ AUDIO_LOG_DEBUG("get_volume_value:%d(%s)=>%f %s", level, __get_volume_type_string_by_idx(volume_type), *value, &dump_str[0]);
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_set_volume_level (void *userdata, audio_info_t *info, uint32_t volume_type, 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);
+
+ if (info == NULL && volume_type < AUDIO_VOLUME_TYPE_VCONF_MAX) {
+
+ /* Update volume level */
+ am->stream.volume_level[volume_type] = level;
+ AUDIO_LOG_INFO("set_volume_level:session(%d), %d(%s)", am->session.session, level, __get_volume_type_string_by_idx(volume_type));
+ }
+#ifdef USE_FMRADIO_V4L2_SPRD
+ if (volume_type == AUDIO_VOLUME_TYPE_MEDIA && am->session.is_radio_on == 1) {
+ audio_ret = _set_volume_level_fmradio(am, level);
+ }
+#endif
+ return audio_ret;
+}
+
+audio_return_t audio_get_gain_value (void *userdata, audio_info_t *info, uint32_t volume_type, double *value)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_gain_table_t *volume_gain_table;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(am->stream.volume_gain_table, AUDIO_ERR_PARAMETER);
+
+ if (info != NULL) {
+ volume_gain_table = am->stream.volume_gain_table;
+ *value = volume_gain_table->gain[info->stream.gain_type];
+ }
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_get_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, 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_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, 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-ucm.c b/tizen-audio-ucm.c
new file mode 100644
index 0000000..c987e30
--- /dev/null
+++ b/tizen-audio-ucm.c
@@ -0,0 +1,466 @@
+/*
+ * 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;
+ }
+ pthread_mutex_init(&(am->ucm.mutex), NULL);
+
+ 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;
+ }
+
+ pthread_mutex_destroy(&am->ucm.mutex);
+
+ 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];
+ int is_radio_dev_on = 0, is_radio_mod_on = 0;
+
+ pthread_mutex_lock(&am->ucm.mutex);
+
+ if (!am->ucm.uc_mgr || !verb) {
+ pthread_mutex_unlock(&am->ucm.mutex);
+ 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;
+
+ if (is_radio_mod_on == 0 && streq(old_mod_list[i], AUDIO_USE_CASE_MODIFIER_FMRADIO)) {
+ is_radio_mod_on = 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;
+
+ if (is_radio_dev_on == 0 && streq(old_dev_list[i], AUDIO_USE_CASE_DEV_FMRADIO)) {
+ is_radio_dev_on = 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);
+ }
+
+ pthread_mutex_unlock(&am->ucm.mutex);
+
+ return audio_ret;
+}
+
+
+audio_return_t _audio_ucm_get_verb (audio_mgr_t *am, const char **value)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
+
+ if ((ret = snd_use_case_get(am->ucm.uc_mgr, "_verb", value)) < 0) {
+ AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
+ ret = AUDIO_ERR_UNDEFINED;
+ }
+
+ return ret;
+}
+
+
+audio_return_t _audio_ucm_reset_use_case (audio_mgr_t *am)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
+
+ if ((ret = snd_use_case_set(am->ucm.uc_mgr, "_verb", AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
+ AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
+ ret = AUDIO_ERR_UNDEFINED;
+ }
+
+ return ret;
+}
+
diff --git a/tizen-audio-util.c b/tizen-audio-util.c
new file mode 100644
index 0000000..5b2477d
--- /dev/null
+++ b/tizen-audio-util.c
@@ -0,0 +1,357 @@
+/*
+ * 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_USE_HW_CONTROL;
+
+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_USE_HW_CONTROL;
+
+close:
+ AUDIO_LOG_ERROR("Error");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(am->mixer.mutex));
+ return -1;
+}
+
+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;
+}
+
+
+/* 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_ERROR("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, uint32_t start_threshold, uint32_t rate)
+{
+ return AUDIO_ERR_NOT_IMPLEMENTED;
+}
diff --git a/tizen-audio.c b/tizen-audio.c
new file mode 100644
index 0000000..9913307
--- /dev/null
+++ b/tizen-audio.c
@@ -0,0 +1,131 @@
+/*
+ * 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"
+
+int audio_get_revision (void)
+{
+ return AUDIO_REVISION;
+}
+
+audio_return_t audio_init (void **userdata, void *platform_data)
+{
+ 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;
+ }
+ am->platform_data = platform_data;
+ memset(&am->cb_intf, 0, sizeof(audio_cb_interface_t));
+ if (AUDIO_IS_ERROR((ret = _audio_session_init(am)))) {
+ AUDIO_LOG_ERROR("session init failed");
+ goto error_exit;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_device_init(am)))) {
+ AUDIO_LOG_ERROR("device init failed");
+ goto error_exit;
+ }
+ if (AUDIO_IS_ERROR((ret = _audio_stream_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_modem_init(am)))) {
+ AUDIO_LOG_ERROR("modem init failed");
+ /* We don't want to stop even though modem 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_session_deinit(am);
+ _audio_device_deinit(am);
+ _audio_stream_deinit(am);
+ _audio_ucm_deinit(am);
+ _audio_modem_deinit(am);
+ _audio_util_deinit(am);
+ free(am);
+ *userdata = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+/* this function is only called from audio tuning app for updating volume */
+audio_return_t audio_reset (void **userdata)
+{
+ audio_mgr_t *am = (audio_mgr_t *)*userdata;
+ audio_return_t ret = AUDIO_RET_OK;
+
+ if (am) {
+ _audio_stream_deinit(am);
+
+ if (AUDIO_IS_ERROR((ret = _audio_stream_init(am)))) {
+ AUDIO_LOG_ERROR("stream init failed");
+ goto error_exit;
+ }
+ }
+
+ return AUDIO_RET_OK;
+
+error_exit:
+ if (am)
+ free(am);
+ *userdata = NULL;
+
+ return ret;
+}
+
+audio_return_t audio_set_callback (void *userdata, audio_cb_interface_t *cb_interface)
+{
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+
+ if (am) {
+ memcpy(&am->cb_intf, cb_interface, sizeof(audio_cb_interface_t));
+ return AUDIO_RET_OK;
+ } else {
+ return AUDIO_ERR_PARAMETER;
+ }
+}
diff --git a/tizen-audio.h b/tizen-audio.h
new file mode 100644
index 0000000..f869889
--- /dev/null
+++ b/tizen-audio.h
@@ -0,0 +1,279 @@
+#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>
+
+#define AUDIO_REVISION 1
+
+/* Error code */
+
+#define AUDIO_IS_ERROR(ret) (ret < 0)
+
+typedef enum audio_return {
+ AUDIO_RET_OK = 0,
+ AUDIO_RET_USE_HW_CONTROL = (int32_t)0x40001000,
+ 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 ;
+
+
+/* Session */
+typedef enum audio_session {
+ AUDIO_SESSION_MEDIA,
+ AUDIO_SESSION_VOICECALL,
+ AUDIO_SESSION_VIDEOCALL,
+ AUDIO_SESSION_VOIP,
+ AUDIO_SESSION_FMRADIO,
+ AUDIO_SESSION_CAMCORDER,
+ AUDIO_SESSION_NOTIFICATION,
+ AUDIO_SESSION_ALARM,
+ AUDIO_SESSION_EMERGENCY,
+ AUDIO_SESSION_VOICE_RECOGNITION,
+ AUDIO_SESSION_MAX
+} audio_session_t;
+
+/* Sub session */
+typedef enum audio_subsession {
+ AUDIO_SUBSESSION_NONE,
+ AUDIO_SUBSESSION_VOICE,
+ AUDIO_SUBSESSION_RINGTONE,
+ AUDIO_SUBSESSION_MEDIA,
+ AUDIO_SUBSESSION_INIT,
+ AUDIO_SUBSESSION_VR_NORMAL,
+ AUDIO_SUBSESSION_VR_DRIVE,
+ AUDIO_SUBSESSION_STEREO_REC,
+ AUDIO_SUBSESSION_MONO_REC,
+ AUDIO_SUBSESSION_MAX
+} audio_subsession_t;
+
+/* Session command */
+typedef enum audio_session_command {
+ AUDIO_SESSION_CMD_START,
+ AUDIO_SESSION_CMD_SUBSESSION,
+ AUDIO_SESSION_CMD_END,
+} audio_session_command_t;
+
+
+/* Direction */
+typedef enum audio_direction {
+ AUDIO_DIRECTION_NONE,
+ AUDIO_DIRECTION_IN, /**< Capture */
+ AUDIO_DIRECTION_OUT, /**< Playback */
+} audio_direction_t;
+
+
+/* Device */
+
+typedef enum audio_device_in {
+ AUDIO_DEVICE_IN_NONE,
+ AUDIO_DEVICE_IN_MIC, /**< Device builtin mic. */
+ AUDIO_DEVICE_IN_WIRED_ACCESSORY, /**< Wired input devices */
+ AUDIO_DEVICE_IN_BT_SCO, /**< Bluetooth SCO device */
+ AUDIO_DEVICE_IN_MAX,
+} audio_device_in_t;
+
+typedef enum audio_device_out {
+ AUDIO_DEVICE_OUT_NONE,
+ AUDIO_DEVICE_OUT_SPEAKER, /**< Device builtin speaker */
+ AUDIO_DEVICE_OUT_RECEIVER, /**< Device builtin receiver */
+ AUDIO_DEVICE_OUT_WIRED_ACCESSORY, /**< Wired output devices such as headphone, headset, and so on. */
+ AUDIO_DEVICE_OUT_BT_SCO, /**< Bluetooth SCO device */
+ AUDIO_DEVICE_OUT_BT_A2DP, /**< Bluetooth A2DP device */
+ AUDIO_DEVICE_OUT_DOCK, /**< DOCK device */
+ AUDIO_DEVICE_OUT_HDMI, /**< HDMI device */
+ AUDIO_DEVICE_OUT_MIRRORING, /**< MIRRORING device */
+ AUDIO_DEVICE_OUT_USB_AUDIO, /**< USB Audio device */
+ AUDIO_DEVICE_OUT_MULTIMEDIA_DOCK, /**< Multimedia DOCK device */
+ AUDIO_DEVICE_OUT_MAX,
+} audio_device_out_t;
+
+typedef enum audio_route_flag {
+ AUDIO_ROUTE_FLAG_NONE = 0,
+ AUDIO_ROUTE_FLAG_MUTE_POLICY = 0x00000001,
+ AUDIO_ROUTE_FLAG_DUAL_OUT = 0x00000002,
+ AUDIO_ROUTE_FLAG_NOISE_REDUCTION = 0x00000010,
+ AUDIO_ROUTE_FLAG_EXTRA_VOL = 0x00000020,
+ AUDIO_ROUTE_FLAG_NETWORK_WB = 0x00000040,
+ AUDIO_ROUTE_FLAG_BT_WB = 0x00000100,
+ AUDIO_ROUTE_FLAG_BT_NREC = 0x00000200,
+ AUDIO_ROUTE_FLAG_VOICE_COMMAND = 0x00040000,
+} audio_route_flag_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;
+
+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;
+
+
+/* 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, /**< Fixed volume type */
+ AUDIO_VOLUME_TYPE_MAX, /**< Volume type count */
+} audio_volume_t;
+
+#define AUDIO_VOLUME_TYPE_VCONF_MAX AUDIO_VOLUME_TYPE_FIXED
+
+typedef enum audio_gain {
+ AUDIO_GAIN_TYPE_DEFAULT,
+ AUDIO_GAIN_TYPE_DIALER,
+ AUDIO_GAIN_TYPE_TOUCH,
+ AUDIO_GAIN_TYPE_AF,
+ AUDIO_GAIN_TYPE_SHUTTER1,
+ AUDIO_GAIN_TYPE_SHUTTER2,
+ AUDIO_GAIN_TYPE_CAMCODING,
+ AUDIO_GAIN_TYPE_MIDI,
+ AUDIO_GAIN_TYPE_BOOTING,
+ AUDIO_GAIN_TYPE_VIDEO,
+ AUDIO_GAIN_TYPE_TTS,
+ AUDIO_GAIN_TYPE_MAX,
+} audio_gain_t;
+
+typedef struct audio_stream_info {
+ char *name;
+ uint32_t samplerate;
+ uint8_t channels;
+ uint32_t volume_type;
+ uint32_t gain_type;
+} audio_stream_info_t ;
+
+
+/* Overall */
+
+typedef struct audio_info {
+ audio_device_info_t device;
+ audio_stream_info_t stream;
+} audio_info_t;
+
+typedef struct audio_cb_interface {
+ audio_return_t (*load_device)(void *platform_data, audio_device_info_t *device_info, audio_device_param_info_t *params);
+ audio_return_t (*open_device)(void *platform_data, audio_device_info_t *device_info, audio_device_param_info_t *params);
+ audio_return_t (*close_all_devices)(void *platform_data);
+ audio_return_t (*close_device)(void *platform_data, audio_device_info_t *device_info);
+ audio_return_t (*unload_device)(void *platform_data, audio_device_info_t *device_info);
+} audio_cb_interface_t;
+
+typedef struct audio_interface {
+ audio_return_t (*init)(void **userdata, void *platform_data);
+ audio_return_t (*deinit)(void **userdata);
+ audio_return_t (*reset)(void **userdata);
+ audio_return_t (*set_callback)(void *userdata, audio_cb_interface_t *cb_interface);
+ audio_return_t (*get_volume_level_max)(void *userdata, uint32_t volume_type, uint32_t *level);
+ audio_return_t (*get_volume_level)(void *userdata, uint32_t volume_type, uint32_t *level);
+ audio_return_t (*get_volume_value)(void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t level, double *value);
+ audio_return_t (*set_volume_level)(void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t level);
+ audio_return_t (*set_volume_value)(void *userdata, audio_info_t *info, uint32_t volume_type, double* value);
+ audio_return_t (*get_gain_value)(void *userdata, audio_info_t *info, uint32_t volume_type, double *value);
+ audio_return_t (*get_mute)(void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t *mute);
+ audio_return_t (*set_mute)(void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t mute);
+ audio_return_t (*set_session)(void *userdata, uint32_t session, uint32_t subsession, uint32_t cmd);
+ audio_return_t (*set_route)(void *userdata, uint32_t session, uint32_t subsession, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+ audio_return_t (*alsa_pcm_open)(void *userdata, void **pcm_handle, char *device_name, uint32_t direction, int mode);
+ audio_return_t (*alsa_pcm_close)(void *userdata, void *pcm_handle);
+ audio_return_t (*set_mixer_value_string)(void *userdata, const char* ctl, const char* value);
+ audio_return_t (*set_route_info)(void *userdata, const char* key, const char* value);
+
+} audio_interface_t;
+
+int audio_get_revision (void);
+audio_return_t audio_init (void **userdata, void *platform_data);
+audio_return_t audio_deinit (void **userdata);
+audio_return_t audio_reset (void **userdata);
+audio_return_t audio_set_callback (void *userdata, audio_cb_interface_t *cb_interface);
+audio_return_t audio_get_volume_level_max (void *userdata, uint32_t volume_type, uint32_t *level);
+audio_return_t audio_get_volume_level (void *userdata, uint32_t volume_type, uint32_t *level);
+audio_return_t audio_get_volume_value (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t level, double *value);
+audio_return_t audio_set_volume_level (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t level);
+audio_return_t audio_set_volume_value (void *userdata, audio_info_t *info, uint32_t volume_type, double* value);
+audio_return_t audio_get_gain_value (void *userdata, audio_info_t *info, uint32_t volume_type, double *value);
+audio_return_t audio_get_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t *mute);
+audio_return_t audio_set_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t mute);
+audio_return_t audio_set_session (void *userdata, uint32_t session, uint32_t subsession, uint32_t cmd);
+audio_return_t audio_alsa_pcm_open (void *userdata, void **pcm_handle, char *device_name, uint32_t direction, int mode);
+audio_return_t audio_alsa_pcm_close (void *userdata, void *pcm_handle);
+audio_return_t audio_set_route (void *userdata, uint32_t session, uint32_t subsession, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+audio_return_t audio_set_mixer_value_string(void *userdata, const char* ctl, const char* value);
+audio_return_t audio_mixer_control_get_value (void *userdata, const char *ctl_name, int *val);
+audio_return_t audio_set_route_info(void *userdata, const char* key, const char* value);
+
+#endif
diff --git a/vb_control_parameters.h b/vb_control_parameters.h
new file mode 100644
index 0000000..0b64e66
--- /dev/null
+++ b/vb_control_parameters.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef VBC_CONTROL_PARAMETERS_H
+#define VBC_CONTROL_PARAMETERS_H
+
+#include "pthread.h"
+
+
+#define BUF_SIZE 1024
+
+#define VBC_PIPE_NAME_MAX_LEN 16
+#define VOIP_PIPE_NAME_MAX VBC_PIPE_NAME_MAX_LEN
+#define NAME_LEN_MAX 16
+
+#define AUDIO_XML_PATH "/usr/etc/audio_hw.xml"
+
+#define MODEM_T_ENABLE_PROPERTY "persist.modem.t.enable"
+#define MODEM_W_ENABLE_PROPERTY "persist.modem.w.enable"
+
+
+typedef enum {
+ CP_W,
+ CP_TG,
+ CP_MAX
+}cp_type_t;
+
+/*support multiple call for multiple modem(cp0/cp1/...):
+different modem is corresponding to different pipe and all pipes use the only vbc.
+support multiple pipe:
+1. change VBC_PIPE_COUNT
+2. change the definition of s_vbc_ctrl_pipe_info.
+3. change channel_id for different cp .On sharp, 0 for cp0, 1 for cp1,2 for ap
+*/
+
+typedef struct
+{
+ char s_vbc_ctrl_pipe_name[VBC_PIPE_NAME_MAX_LEN];
+ int channel_id;
+ cp_type_t cp_type;
+}vbc_ctrl_pipe_para_t;
+
+
+struct voip_res
+{
+ cp_type_t cp_type;
+ int8_t pipe_name[VOIP_PIPE_NAME_MAX];
+ int channel_id;
+ int enable;
+ int is_done;
+ void *adev;
+ pthread_t thread_id;
+};
+
+typedef struct
+{
+ int8_t index;
+ int is_switch;
+ int8_t is_ext;
+}i2s_ctl_t;
+
+
+
+typedef struct debuginfo
+{
+ int enable;
+ int sleeptime_gate;
+ int pcmwritetime_gate;
+ int lastthis_outwritetime_gate;
+}debuginfo;
+
+typedef struct{
+ int num;
+ vbc_ctrl_pipe_para_t *vbc_ctrl_pipe_info;
+ i2s_ctl_t i2s_bt;
+ i2s_ctl_t i2s_extspk;
+ struct voip_res voip_res;
+ debuginfo debug_info;
+}audio_modem_t;
+
+/*audio mode structure,we can expand for more fields if necessary*/
+typedef struct
+{
+ int index;
+ char mode_name[NAME_LEN_MAX];
+
+}audio_mode_item_t;
+
+/*we mostly have four mode,(headset,headfree,handset,handsfree),
+ differet product may configure different mode number,htc have 25 modes.*/
+typedef struct{
+ int num;
+ audio_mode_item_t *audio_mode_item_info;
+}aud_mode_t;
+struct modem_config_parse_state{
+ audio_modem_t *modem_info;
+ vbc_ctrl_pipe_para_t *vbc_ctrl_pipe_info;
+ aud_mode_t *audio_mode_info;
+ audio_mode_item_t *audio_mode_item_info;
+};
+
+#endif
+