summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjk7744.park <jk7744.park@samsung.com>2015-01-31 05:49:15 (GMT)
committerjk7744.park <jk7744.park@samsung.com>2015-01-31 05:49:15 (GMT)
commit9cdfea08c8d09c9bd00e3b5ac0fe092b0178848b (patch)
tree28f203ae42a5167e41ef42d5202ae91ef9f5ef62
parent9e903909f52eb033e2b156f65e585206032157ac (diff)
downloadaudio-hal-e4x12-tizen_2.3.zip
audio-hal-e4x12-tizen_2.3.tar.gz
audio-hal-e4x12-tizen_2.3.tar.bz2
-rwxr-xr-x[-rw-r--r--]LICENSE.Apache-2.0 (renamed from LICENSE.APLv2)2
-rwxr-xr-x[-rw-r--r--]Makefile.am1
-rwxr-xr-xaudio_hal_sys_file_access.efl1
-rwxr-xr-x[-rw-r--r--]configure.ac2
-rwxr-xr-x[-rw-r--r--]packaging/audio-hal-e4x12.spec22
-rwxr-xr-x[-rw-r--r--]tizen-audio-device.c423
-rwxr-xr-x[-rw-r--r--]tizen-audio-internal.h125
-rwxr-xr-x[-rw-r--r--]tizen-audio-session.c125
-rwxr-xr-x[-rw-r--r--]tizen-audio-stream.c188
-rwxr-xr-xtizen-audio-ucm.c447
-rwxr-xr-x[-rw-r--r--]tizen-audio-util.c291
-rwxr-xr-x[-rw-r--r--]tizen-audio.c38
-rwxr-xr-x[-rw-r--r--]tizen-audio.h122
13 files changed, 1597 insertions, 190 deletions
diff --git a/LICENSE.APLv2 b/LICENSE.Apache-2.0
index 76f9119..d645695 100644..100755
--- a/LICENSE.APLv2
+++ b/LICENSE.Apache-2.0
@@ -1,4 +1,3 @@
-Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
Apache License
Version 2.0, January 2004
@@ -201,4 +200,3 @@ Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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
index e328e7f..af5fec7 100644..100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,7 @@ 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-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)
diff --git a/audio_hal_sys_file_access.efl b/audio_hal_sys_file_access.efl
new file mode 100755
index 0000000..7725046
--- /dev/null
+++ b/audio_hal_sys_file_access.efl
@@ -0,0 +1 @@
+pulseaudio _ rwx--- ------
diff --git a/configure.ac b/configure.ac
index 7c2da00..c61c78a 100644..100755
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.67])
-AC_INIT([libaudiofilters-sec], [0.1])
+AC_INIT([audio-hal-e4x12], [0.1])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_HEADERS([config.h])
diff --git a/packaging/audio-hal-e4x12.spec b/packaging/audio-hal-e4x12.spec
index 488d159..096b384 100644..100755
--- a/packaging/audio-hal-e4x12.spec
+++ b/packaging/audio-hal-e4x12.spec
@@ -1,16 +1,17 @@
Name: audio-hal-e4x12
Summary: TIZEN Audio HAL for Exynos4x12
-Version: 0.1.5
+Version: 0.1.9
Release: 0
VCS: magnolia/adaptation/ap_samsung/audio-hal-e4x12#a568942051241d60e37c6738466a2a5058f260c0
Group: System/Libraries
License: Apache-2.0
URL: http://tizen.org
Source0: audio-hal-e4x12-%{version}.tar.gz
-BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(vconf)
BuildRequires: pkgconfig(iniparser)
BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(alsa)
+Provides: libtizen-audio.so
%description
TIZEN Audio HAL for Exynos4x12
@@ -19,11 +20,9 @@ TIZEN Audio HAL for Exynos4x12
%setup -q -n %{name}-%{version}
%build
-%if 0%{?tizen_build_binary_release_type_eng}
-export CFLAGS="$CFLAGS -DTIZEN_ENGINEER_MODE"
-export CXXFLAGS="$CXXFLAGS –DTIZEN_ENGINEER_MODE"
-export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE"
-%endif
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS ?“DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
%autogen
%configure
@@ -32,10 +31,10 @@ make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
-
+mkdir -p %{buildroot}/etc/smack/accesses.d
+cp -arf audio_hal_sys_file_access.efl %{buildroot}/etc/smack/accesses.d
mkdir -p %{buildroot}/usr/share/license
-cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name}
-
+cp LICENSE.Apache-2.0 %{buildroot}/usr/share/license/%{name}
%make_install
%post
@@ -47,5 +46,6 @@ cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name}
%files
%manifest audio-hal-e4x12.manifest
%defattr(-,root,root,-)
+/etc/smack/accesses.d/audio_hal_sys_file_access.efl
/usr/lib/libtizen-audio.so
-%{_datadir}/license/%{name}
+/usr/share/license/%{name}
diff --git a/tizen-audio-device.c b/tizen-audio-device.c
index 541285a..8a0b831 100644..100755
--- a/tizen-audio-device.c
+++ b/tizen-audio-device.c
@@ -3,8 +3,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -36,6 +34,11 @@ audio_return_t _audio_device_init (audio_mgr_t *am)
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;
return AUDIO_RET_OK;
}
@@ -47,25 +50,425 @@ audio_return_t _audio_device_deinit (audio_mgr_t *am)
return AUDIO_RET_OK;
}
+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) {
+ device_info->name = malloc(strlen(device_info->alsa.card_name) + 6); /* 6 = "hw: ,idx */
+ sprintf(device_info->name, "hw:%s,%d", device_info->alsa.card_name, device_info->alsa.device_idx);
+ if (device_info->direction == AUDIO_DIRECTION_OUT) {
+ /* ALSA playback */
+ switch (device_info->alsa.device_idx) {
+ /* default device */
+ case 0:
+ case 3:
+ 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;
+ /* HDMI device */
+ case 1:
+ /* VOICE PCM. */
+ break;
+ default:
+ AUDIO_LOG_INFO("Unknown Playback Device");
+ break;
+ }
+ } else if (device_info->direction == AUDIO_DIRECTION_IN) {
+ /* ALSA capture */
+ 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 = 48000;
+ params[dev_param_count].param = AUDIO_DEVICE_PARAM_ALTERNATE_RATE;
+ params[dev_param_count++].u32_v = 48000;
+ break;
+ default:
+ AUDIO_LOG_INFO("Unknown Capture Device");
+ break;
+ }
+ }
+
+ 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]);
+ }
+}
+
+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;
+ 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:
+ 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;
+ /* 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;
+ }
+ }
+
+ /* 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 _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;
- bool update_volume = false;
+ 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 (am->device.active_out != device_out)
- update_volume = true;
+ if ((session == AUDIO_SESSION_VOICECALL) && (subsession == AUDIO_SUBSESSION_VOICE)) {
+ 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 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 {
+ 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);
+ }
+ }
- am->device.active_in = device_in;
- am->device.active_out = device_out;
+ 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_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;
- /* Volume level should be updated if device changed */
- if (update_volume)
- audio_ret = _audio_update_volume_level(am);
+ 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;
+}
+static int __voice_pcm_set_params (audio_mgr_t *am, snd_pcm_t *pcm)
+{
+ snd_pcm_hw_params_t *params = NULL;
+ int err = 0;
+ unsigned int val = 0;
+
+ /* Skip parameter setting to null device. */
+ if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
+ return AUDIO_ERR_IOCTL;
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(&params);
+
+ /* Fill it in with default values. */
+ if (snd_pcm_hw_params_any(pcm, params) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Set the desired hardware parameters. */
+ /* Interleaved mode */
+ err = snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+ err = snd_pcm_hw_params_set_rate(pcm, params, (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 _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->device.pcm_out, 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->device.pcm_out);
+
+ AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
+
+ /* Get capture voice-pcm from ucm conf. Open and set-params */
+ if ((audio_ret = audio_alsa_pcm_open((void *)am, (void **)&am->device.pcm_in, 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->device.pcm_in);
+
+ AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
+
+ return ret;
+}
+
+int _voice_pcm_close (audio_mgr_t *am,int reset)
+{
+ AUDIO_LOG_INFO("close voice pcm handles");
+
+ if (am->device.pcm_out) {
+ audio_alsa_pcm_close((void *)am, am->device.pcm_out);
+ am->device.pcm_out = NULL;
+ AUDIO_LOG_INFO("pcm playback device close");
+ }
+
+ if (am->device.pcm_in) {
+ audio_alsa_pcm_close((void *)am, am->device.pcm_in);
+ am->device.pcm_in = NULL;
+ AUDIO_LOG_INFO("pcm capture device close");
+ }
+ if (reset)
+ _reset_route(am, 1);
+
+ return 0;
+}
diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h
index 6594f0e..d735f60 100644..100755
--- a/tizen-audio-internal.h
+++ b/tizen-audio-internal.h
@@ -6,8 +6,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -22,15 +20,21 @@
*
*/
-#include <asoundlib.h>
#include <dlog.h>
-
+#include <time.h>
+#include <sys/types.h>
+#include <asoundlib.h>
+#include <pthread.h>
+#include <use-case.h>
#include "tizen-audio.h"
/* Debug */
//#define AUDIO_DEBUG
+#define PROPERTY_VALUE_MAX 92
+#define BUF_SIZE 1024
#define AUDIO_DUMP_STR_LEN 256
+#define AUDIO_DEVICE_INFO_LIST_MAX 16
#ifdef USE_DLOG
#ifdef DLOG_TAG
#undef DLOG_TAG
@@ -49,7 +53,7 @@
#define AUDIO_LOG_VERBOSE(...) fprintf(stdout, __VA_ARGS__)
#endif
-#define AUDIO_RETURN_IF_FAIL(expr, val) do { \
+#define AUDIO_RETURN_IF_FAIL(expr) do { \
if (!expr) { \
AUDIO_LOG_ERROR("%s failed", #expr); \
return; \
@@ -62,18 +66,71 @@
} \
} while (0)
+/* Verbs */
+#define AUDIO_USE_CASE_VERB_INACTIVE "Inactive"
+#define AUDIO_USE_CASE_VERB_HIFI "HiFi"
+#define AUDIO_USE_CASE_VERB_VOICECALL "VoiceCall"
+#define AUDIO_USE_CASE_VERB_LOOPBACK "Loopback"
+#define AUDIO_USE_CASE_VERB_FMRADIO "FM_Radio"
+
+/* 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_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 streq !strcmp
+#define strneq strcmp
+
+#define ALSA_DEFAULT_CARD "wm1811"
+#define VOICE_PCM_DEVICE "hw:0,1"
+
+#define MAX_DEVICES 5
+#define MAX_MODIFIERS 5
+
+/* type definitions */
+typedef signed char int8_t;
+
+/* pcm */
+typedef struct {
+ snd_pcm_format_t format;
+ uint32_t rate;
+ uint8_t channels;
+} audio_pcm_sample_spec_t;
+
/* 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;
} audio_device_mgr_t;
@@ -102,29 +159,77 @@ enum {
};
typedef struct audio_stream_mgr {
- uint32_t volume_level[AUDIO_VOLUME_TYPE_MAX];
+ uint32_t volume_level[AUDIO_VOLUME_DEVICE_MAX][AUDIO_VOLUME_TYPE_MAX];
audio_volume_gain_table_t *volume_gain_table;
} audio_stream_mgr_t;
+typedef struct audio_ucm_mgr {
+ snd_use_case_mgr_t* uc_mgr;
+} audio_ucm_mgr_t;
+
typedef struct audio_mixer_mgr {
+ snd_mixer_t *mixer;
pthread_mutex_t mutex;
+ struct {
+ snd_ctl_elem_value_t *value;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ } control;
} audio_mixer_mgr_t;
/* Overall */
typedef struct audio_mgr {
+ 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_mgr_t;
+typedef struct {
+ unsigned short is_open; /* if is_open is true, open device; else close device.*/
+ unsigned short is_headphone;
+ unsigned int is_downlink_mute;
+ unsigned int is_uplink_mute;
+} device_ctrl_t;
+
+typedef struct samplerate_ctrl {
+ unsigned int samplerate; /* change samplerate.*/
+} set_samplerate_t;
+
audio_return_t _audio_stream_init (audio_mgr_t *am);
audio_return_t _audio_stream_deinit (audio_mgr_t *am);
-audio_return_t _audio_update_volume_level (audio_mgr_t *am);
audio_return_t _audio_device_init (audio_mgr_t *am);
audio_return_t _audio_device_deinit (audio_mgr_t * am);
-
-
+audio_return_t _set_route_voicecall (audio_mgr_t *am, uint32_t device_in, uint32_t device_out, uint32_t route_flag);
+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);
+int _voice_pcm_open(audio_mgr_t *am);
+int _voice_pcm_close(audio_mgr_t *am, int reset);
+audio_return_t _audio_ucm_get_verb (audio_mgr_t *am, const char **value);
+audio_return_t _audio_ucm_reset_use_case (audio_mgr_t *am);
+
+audio_return_t _audio_util_init (audio_mgr_t *am);
+audio_return_t _audio_util_deinit (audio_mgr_t *am);
+audio_return_t _audio_mixer_control_set_param(audio_mgr_t *am, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
+audio_return_t _audio_mixer_control_set_value(audio_mgr_t *am, const char *ctl_name, int val);
+audio_return_t _audio_mixer_control_set_value_string(audio_mgr_t *am, const char* ctl_name, const char* value);
+audio_return_t _audio_mixer_control_get_value(audio_mgr_t *am, const char *ctl_name, int *val);
+audio_return_t _audio_mixer_control_get_element(audio_mgr_t *am, const char *ctl_name, snd_hctl_elem_t **elem);
+
+audio_return_t _audio_pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event, 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-session.c b/tizen-audio-session.c
index e533799..3f3daa0 100644..100755
--- a/tizen-audio-session.c
+++ b/tizen-audio-session.c
@@ -3,8 +3,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -29,12 +27,58 @@
#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;
}
@@ -46,18 +90,85 @@ audio_return_t _audio_session_deinit (audio_mgr_t *am)
return AUDIO_RET_OK;
}
-audio_return_t audio_set_session (void *userdata, uint32_t session, uint32_t subsession)
+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:%d,%d", session, subsession);
+ 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_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)) {
+ if(am->device.pcm_out || am->device.pcm_in) {
+ _voice_pcm_close(am, 1);
+ }
+ AUDIO_LOG_INFO("unset call session");
+ am->session.is_call_session = 0;
+ }
- am->session.session = session;
- am->session.subsession = subsession;
+ 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_MEDIA && (prev_subsession == AUDIO_SUBSESSION_STEREO_REC || AUDIO_SUBSESSION_MONO_REC)) {
+ am->session.is_recording = 0;
+ }
+ am->session.session = AUDIO_SESSION_MEDIA;
+ am->session.subsession = AUDIO_SUBSESSION_NONE;
+ } 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;
+ }
+ if (prev_subsession != AUDIO_SUBSESSION_VOICE && subsession == AUDIO_SUBSESSION_VOICE){
+ if(!am->device.pcm_out || !am->device.pcm_in) {
+ _voice_pcm_open(am);
+ }
+ } else if (prev_subsession == AUDIO_SUBSESSION_VOICE && subsession != AUDIO_SUBSESSION_VOICE) {
+ if(am->device.pcm_out || am->device.pcm_in) {
+ _voice_pcm_close(am, 1);
+ }
+ }
+ }
+ am->session.subsession = subsession;
+ if (prev_subsession != subsession && subsession == AUDIO_SUBSESSION_VOICE) {
+ 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
index 0c263ae..017ff79 100644..100755
--- a/tizen-audio-stream.c
+++ b/tizen-audio-stream.c
@@ -3,8 +3,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -26,9 +24,9 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
+#include <math.h>
#include <vconf.h>
#include <iniparser.h>
-#include <alsa/asoundlib.h>
#include "tizen-audio-internal.h"
@@ -42,6 +40,7 @@ enum {
STREAM_DEVICE_HEADSET,
STREAM_DEVICE_BLUETOOTH,
STREAM_DEVICE_HDMI,
+ STREAM_DEVICE_DOCK,
STREAM_DEVICE_MAX,
};
@@ -53,14 +52,26 @@ static const char *g_volume_vconf[AUDIO_VOLUME_TYPE_MAX] = {
"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/svoice", /* AUDIO_VOLUME_TYPE_SVOICE */
+ "file/private/sound/volume/voice", /* AUDIO_VOLUME_TYPE_VOICE */
"file/private/sound/volume/fixed", /* AUDIO_VOLUME_TYPE_FIXED */
- "file/private/sound/volume/java" /* AUDIO_VOLUME_TYPE_EXT_JAVA */
};
static inline uint8_t __get_volume_dev_index(audio_mgr_t *am, uint32_t volume_type)
{
- return 0;
+
+ 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)
@@ -71,11 +82,11 @@ static const uint8_t __get_stream_dev_index (uint32_t device_out)
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_SPEAKER;
+ 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_SPEAKER;
+ case AUDIO_DEVICE_OUT_MULTIMEDIA_DOCK: return STREAM_DEVICE_DOCK;
default:
AUDIO_LOG_DEBUG("invalid device_out:%d", device_out);
break;
@@ -91,16 +102,7 @@ static const char *__get_device_string_by_idx (uint32_t dev_idx)
case STREAM_DEVICE_HEADSET: return "headset";
case STREAM_DEVICE_BLUETOOTH: return "btheadset";
case STREAM_DEVICE_HDMI: return "hdmi";
- default: return "invalid";
- }
-}
-
-static const char *__get_direction_string_by_idx (uint32_t dir_idx)
-{
- switch (dir_idx) {
- case AUDIO_DIRECTION_NONE: return "none";
- case AUDIO_DIRECTION_IN: return "in";
- case AUDIO_DIRECTION_OUT: return "out";
+ case STREAM_DEVICE_DOCK: return "dock";
default: return "invalid";
}
}
@@ -115,9 +117,8 @@ static const char *__get_volume_type_string_by_idx (uint32_t vol_type_idx)
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_SVOICE: return "svoice";
+ case AUDIO_VOLUME_TYPE_VOICE: return "voice";
case AUDIO_VOLUME_TYPE_FIXED: return "fixed";
- case AUDIO_VOLUME_TYPE_EXT_JAVA: return "java";
default: return "invalid";
}
}
@@ -143,20 +144,22 @@ static const char *__get_gain_type_string_by_idx (uint32_t gain_type_idx)
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 = sprintf(dump, "device:alsa(%d.%d)", info->device.alsa.card_idx, info->device.alsa.device_idx);
+ 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 = sprintf(dump, "device:bluez(%s,nrec:%d)", info->device.bluez.protocol, info->device.bluez.nrec);
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "device:bluez(%s,nrec:%d)", info->device.bluez.protocol, info->device.bluez.nrec);
} else {
- len = sprintf(dump, "device:unknown");
+ len = snprintf(dump, AUDIO_DUMP_STR_LEN, "device:unknown");
}
if (len > 0)
dump += len;
- len = sprintf(dump, "stream:%s(%dhz,%dch,vol:%s,gain:%s)",
- info->stream.name ? info->stream.name : "null", info->stream.samplerate, info->stream.channels,
+ 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)
@@ -165,7 +168,6 @@ static void __dump_info(char *dump, audio_info_t *info)
*dump = '\0';
}
-#ifdef AUDIO_DEBUG
static void __dump_tb (audio_mgr_t *am)
{
audio_volume_gain_table_t *volume_gain_table = am->stream.volume_gain_table;
@@ -186,12 +188,12 @@ static void __dump_tb (audio_mgr_t *am)
char dump_str[AUDIO_DUMP_STR_LEN], *dump_str_ptr;
/* Dump volume table */
- AUDIO_LOG_DEBUG("<<<<< volume table >>>>>");
+ AUDIO_LOG_INFO("<<<<< volume table >>>>>");
for (dev_idx = 0; dev_idx < STREAM_DEVICE_MAX; dev_idx++) {
const char *dev_str = __get_device_string_by_idx(dev_idx);
- AUDIO_LOG_DEBUG("<< %s >>", dev_str);
+ AUDIO_LOG_INFO("<< %s >>", dev_str);
for (vol_type_idx = 0; vol_type_idx < AUDIO_VOLUME_TYPE_MAX; vol_type_idx++) {
const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
@@ -205,7 +207,7 @@ static void __dump_tb (audio_mgr_t *am)
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_DEBUG("%s", dump_str);
+ AUDIO_LOG_INFO("%s", dump_str);
}
volume_gain_table++;
}
@@ -213,7 +215,7 @@ static void __dump_tb (audio_mgr_t *am)
volume_gain_table = am->stream.volume_gain_table;
/* Dump gain table */
- AUDIO_LOG_DEBUG("<<<<< gain table >>>>>");
+ AUDIO_LOG_INFO("<<<<< gain table >>>>>");
dump_str_ptr = &dump_str[0];
memset(dump_str, 0x00, sizeof(char) * sizeof(dump_str));
@@ -225,7 +227,7 @@ static void __dump_tb (audio_mgr_t *am)
snprintf(dump_str_ptr, 7, "%5s ", gain_type_str[gain_type_idx]);
dump_str_ptr += strlen(dump_str_ptr);
}
- AUDIO_LOG_DEBUG("%s", dump_str);
+ AUDIO_LOG_INFO("%s", dump_str);
for (dev_idx = 0; dev_idx < STREAM_DEVICE_MAX; dev_idx++) {
const char *dev_str = __get_device_string_by_idx(dev_idx);
@@ -240,22 +242,22 @@ static void __dump_tb (audio_mgr_t *am)
snprintf(dump_str_ptr, 7, "%01.3f ", volume_gain_table->gain[gain_type_idx]);
dump_str_ptr += strlen(dump_str_ptr);
}
- AUDIO_LOG_DEBUG("%s", dump_str);
+ AUDIO_LOG_INFO("%s", dump_str);
volume_gain_table++;
}
}
-#endif
static audio_return_t __load_volume_gain_table_from_ini (audio_mgr_t *am)
{
dictionary * dict = NULL;
uint32_t dev_idx, 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;
dict = iniparser_load(VOLUME_INI_TEMP_PATH);
if (!dict) {
- AUDIO_LOG_DEBUG("Use temporary volume&gain ini file");
+ 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");
@@ -273,18 +275,23 @@ static audio_return_t __load_volume_gain_table_from_ini (audio_mgr_t *am)
const char *vol_type_str = __get_volume_type_string_by_idx(vol_type_idx);
volume_gain_table->volume_level_max[vol_type_idx] = 0;
-
- key = malloc(strlen(dev_str) + strlen(vol_type_str) + 2);
+ size = strlen(dev_str) + strlen(vol_type_str) + 2;
+ key = malloc(size);
if (key) {
- sprintf(key, "%s:%s", dev_str, vol_type_str);
+ snprintf(key, size, "%s:%s", dev_str, vol_type_str);
list_str = iniparser_getstr(dict, key);
if (list_str) {
token = strtok_r(list_str, delimiter, &ptr);
while (token) {
- volume_gain_table->volume[vol_type_idx][volume_gain_table->volume_level_max[vol_type_idx]++] = atof(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;
}
@@ -294,54 +301,71 @@ static audio_return_t __load_volume_gain_table_from_ini (audio_mgr_t *am)
}
/* Load gain table */
- key = malloc(strlen(dev_str) + strlen("gain") + 2);
- if (key) {
- sprintf(key, "%s:gain", dev_str);
- list_str = iniparser_getstr(dict, key);
- if (list_str) {
- token = strtok_r(list_str, delimiter, &ptr);
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(dev_str) + strlen("gain") + strlen(gain_type_str) + 3;
+ key = malloc(size);
+ if (key) {
+ snprintf(key, size, "%s:gain_%s", dev_str, gain_type_str);
+ token = iniparser_getstr(dict, key);
if (token) {
volume_gain_table->gain[gain_type_idx] = atof(token);
- token = strtok_r(NULL, delimiter, &ptr);
} else {
volume_gain_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
}
- }
+ free(key);
} else {
- for (gain_type_idx = 0; gain_type_idx < AUDIO_GAIN_TYPE_MAX; gain_type_idx++)
volume_gain_table->gain[gain_type_idx] = GAIN_VALUE_MAX;
}
- free(key);
}
volume_gain_table++;
}
iniparser_freedict(dict);
-#ifdef AUDIO_DEBUG
+
__dump_tb(am);
-#endif
return AUDIO_RET_OK;
}
audio_return_t _audio_stream_init (audio_mgr_t *am)
{
- int i, value;
+ int i, j;
+ char *str = NULL;
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int init_value[AUDIO_VOLUME_TYPE_MAX] = { 9, 11, 7, 11, 7, 4, 4, 7, 4, 0 };
AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
+ for (j = 0; j < AUDIO_VOLUME_DEVICE_MAX; j++) {
+ am->stream.volume_level[j][i] = init_value[i];
+ }
+ }
+
+ for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
/* Get volume value string from VCONF */
- if (vconf_get_int(g_volume_vconf[i], &value) != 0) {
- AUDIO_LOG_ERROR("vconf_get_int(%s) failed", g_volume_vconf[i]);
+ if((str = vconf_get_str(g_volume_vconf[i])) == NULL) {
+ AUDIO_LOG_ERROR("vconf_get_str(%s) failed", g_volume_vconf[i]);
continue;
}
- AUDIO_LOG_INFO("read vconf. %s = %d", g_volume_vconf[i], value);
+
+ AUDIO_LOG_INFO("read vconf. %s = %s", g_volume_vconf[i], str);
/* Unified type uses only fisrt index of volume devices */
- am->stream.volume_level[i] = value;
+
+ for (j = 0; j < AUDIO_VOLUME_DEVICE_MAX; j++) {
+ char val[3];
+ memset(val, 0, sizeof(val));
+ val[0] = str[j*2];
+ val[1] = str[j*2+1];
+ am->stream.volume_level[j][i] = atoi(val);
+ }
+
+ if (str)
+ free(str);
}
if (!(am->stream.volume_gain_table = malloc(STREAM_DEVICE_MAX * sizeof(audio_volume_gain_table_t)))) {
@@ -349,7 +373,13 @@ audio_return_t _audio_stream_init (audio_mgr_t *am)
return AUDIO_ERR_RESOURCE;
}
- return __load_volume_gain_table_from_ini(am);
+ 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;
+ }
+
+ return audio_ret;
}
audio_return_t _audio_stream_deinit (audio_mgr_t *am)
@@ -387,7 +417,7 @@ audio_return_t audio_get_volume_level (void *userdata, uint32_t volume_type, uin
AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
- *level = am->stream.volume_level[volume_type];
+ *level = am->stream.volume_level[__get_volume_dev_index(am, volume_type)][volume_type];
return AUDIO_RET_OK;
}
@@ -401,9 +431,7 @@ audio_return_t audio_get_volume_value (void *userdata, audio_info_t *info, uint3
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 + __get_stream_dev_index(am->device.active_out);
if (volume_gain_table->volume_level_max[volume_type] < level)
@@ -420,28 +448,32 @@ audio_return_t audio_get_volume_value (void *userdata, audio_info_t *info, uint3
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) {
+
/* Update volume level */
- am->stream.volume_level[volume_type] = level;
+ am->stream.volume_level[__get_volume_dev_index(am, volume_type)][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));
}
- return AUDIO_RET_OK;
+ return audio_ret;
}
-audio_return_t _audio_update_volume_level (audio_mgr_t *am)
+audio_return_t audio_get_gain_value (void *userdata, audio_info_t *info, uint32_t volume_type, double *value)
{
- int i;
+ audio_mgr_t *am = (audio_mgr_t *)userdata;
+ audio_volume_gain_table_t *volume_gain_table;
- for (i = 0; i < AUDIO_VOLUME_TYPE_MAX; i++) {
- /* Update vconf */
- if (vconf_set_int(g_volume_vconf[i], am->stream.volume_level[i]) != 0) {
- AUDIO_LOG_ERROR("vconf_set_int(%s) failed", g_volume_vconf[i]);
- continue;
- }
+ 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 + __get_stream_dev_index(am->device.active_out);
+ *value = volume_gain_table->gain[info->stream.gain_type];
}
return AUDIO_RET_OK;
@@ -449,9 +481,23 @@ audio_return_t _audio_update_volume_level (audio_mgr_t *am)
audio_return_t audio_get_mute (void *userdata, audio_info_t *info, uint32_t volume_type, uint32_t direction, uint32_t *mute)
{
- return AUDIO_RET_OK; }
+ 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)
{
- return AUDIO_RET_OK;
+ 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 100755
index 0000000..0d4f437
--- /dev/null
+++ b/tizen-audio-ucm.c
@@ -0,0 +1,447 @@
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef ALSA_UCM_DEBUG_TIME
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include "tizen-audio-internal.h"
+
+#ifdef ALSA_UCM_DEBUG_TIME
+#define SND_USE_CASE_SET __set_use_case_with_time
+#else
+#define SND_USE_CASE_SET snd_use_case_set
+#endif
+
+audio_return_t _audio_ucm_init (audio_mgr_t *am)
+{
+ snd_use_case_mgr_open(&am->ucm.uc_mgr, ALSA_DEFAULT_CARD);
+
+ if (!am->ucm.uc_mgr) {
+ AUDIO_LOG_ERROR("uc_mgr open failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_ucm_deinit (audio_mgr_t *am)
+{
+ if (am->ucm.uc_mgr != NULL) {
+ snd_use_case_mgr_close(am->ucm.uc_mgr);
+ am->ucm.uc_mgr = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
+void _audio_ucm_get_device_name (audio_mgr_t *am, const char *use_case, audio_direction_t direction, const char **value)
+{
+ char identifier[70] = {0};
+
+ if (direction == AUDIO_DIRECTION_IN) {
+ sprintf(identifier, "CapturePCM//%s", use_case);
+ } else {
+ sprintf(identifier, "PlaybackPCM//%s", use_case);
+ }
+ snd_use_case_get(am->ucm.uc_mgr, identifier, value);
+}
+
+static inline void __add_ucm_device_info (audio_mgr_t *am, const char *use_case, audio_direction_t direction, audio_device_info_t *device_info_list, int *device_info_count)
+{
+ audio_device_info_t *device_info;
+ const char *device_name = NULL;
+ char *needle = NULL;
+
+ _audio_ucm_get_device_name(am, use_case, direction, &device_name);
+ if (device_name) {
+ device_info = &device_info_list[(*device_info_count)++];
+
+ memset(device_info, 0x00, sizeof(audio_device_info_t));
+ device_info->api = AUDIO_DEVICE_API_ALSA;
+ device_info->direction = direction;
+ needle = strstr(&device_name[3], ",");
+ if (needle) {
+ device_info->alsa.device_idx = *(needle+1) - '0';
+ device_info->alsa.card_name = strndup(&device_name[3], needle - (device_name+3));
+ device_info->alsa.card_idx = snd_card_get_index(device_info->alsa.card_name);
+ AUDIO_LOG_DEBUG("Card name: %s", device_info->alsa.card_name);
+ }
+
+ free((void *)device_name);
+ }
+}
+
+int _audio_ucm_fill_device_info_list (audio_mgr_t *am, audio_device_info_t *device_info_list, const char *verb)
+{
+ int device_info_count = 0;
+ const char *curr_verb = NULL;
+
+ if (!verb) {
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &curr_verb);
+ verb = curr_verb;
+ }
+
+ /* prepare destination */
+ /*If the devices are VOICECALL LOOPBACK or FMRADIO then pulseaudio need not get the device notification*/
+ if (verb) {
+ if (strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, strlen(AUDIO_USE_CASE_VERB_VOICECALL)) &&
+ strncmp(verb, AUDIO_USE_CASE_VERB_LOOPBACK, strlen(AUDIO_USE_CASE_VERB_LOOPBACK))) {
+ __add_ucm_device_info(am, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
+ if(strncmp(verb, AUDIO_USE_CASE_VERB_FMRADIO, strlen(AUDIO_USE_CASE_VERB_FMRADIO))) {
+ __add_ucm_device_info(am, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
+ }
+ }
+
+ if (curr_verb)
+ free((void *)curr_verb);
+
+ }
+
+ return device_info_count;
+}
+
+static void __dump_use_case(const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count, char *dump)
+{
+ int i, len;
+
+ len = sprintf(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
+ if (len > 0)
+ dump += len;
+
+ for (i = 0; i < dev_count; i++) {
+ if (i != dev_count - 1) {
+ len = sprintf(dump, "%s, ", devices[i]);
+ } else {
+ len = sprintf(dump, "%s", devices[i]);
+ }
+ if (len > 0)
+ dump += len;
+ }
+
+ len = sprintf(dump, " ] Modifier [ ");
+ if (len > 0)
+ dump += len;
+
+ for (i = 0; i < mod_count; i++) {
+ if (i != mod_count - 1) {
+ len = sprintf(dump, "%s, ", modifiers[i]);
+ } else {
+ len = sprintf(dump, "%s", modifiers[i]);
+ }
+ if (len > 0)
+ dump += len;
+ }
+
+ len = sprintf(dump, " ]");
+ if (len > 0)
+ dump += len;
+
+ *dump = '\0';
+}
+
+#ifdef ALSA_UCM_DEBUG_TIME
+static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
+{
+ int ret = 0;
+ struct timeval t_start, t_stop;
+ unsigned long long t_diff = 0;
+
+ gettimeofday(&t_start, NULL);
+ ret = snd_use_case_set(uc_mgr, identifier, value);
+ gettimeofday(&t_stop, NULL);
+ if (t_start.tv_sec < t_stop.tv_sec)
+ t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
+ t_diff += (t_stop.tv_usec - t_start.tv_usec);
+ AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
+
+ return ret;
+}
+#endif
+
+/* UCM sequence
+ 1) If verb is null or verb is not changed
+ 1-1) If device is changed
+ (If there is request for same device, it will be ignored)
+ -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
+ (playback/capture device will be enabled again if there is no request for playback/capture device)
+ 1-2) If device is not changed
+ 1-2-1) If modifier is changed
+ (If there is request for same modifier, it will be ignored)
+ -> Disable modifiers, enable modifiers
+ 2) If verb is changed
+ -> Reset, set new verb, enable devices & modifiers
+ */
+audio_return_t _audio_ucm_set_use_case (audio_mgr_t *am, const char *verb, const char *devices[], const char *modifiers[])
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
+ const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
+ int old_dev_count = 0, dev_count = 0;
+ int old_mod_count = 0, mod_count = 0;
+ const char **dis_dev_list = NULL, **ena_dev_list = NULL;
+ const char **dis_mod_list = NULL, **ena_mod_list = NULL;
+ int dis_dev_count = 0, ena_dev_count = 0;
+ int dis_mod_count = 0, ena_mod_count = 0;
+ int i = 0, j = 0;
+ char dump_str[512];
+
+ if (!am->ucm.uc_mgr || !verb)
+ return AUDIO_ERR_PARAMETER;
+
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
+ old_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &old_dev_list);
+ old_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &old_mod_list);
+ __dump_use_case(old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
+
+ if (devices) {
+ for (dev_count = 0; devices[dev_count]; dev_count++);
+ }
+ if (modifiers) {
+ for (mod_count = 0; modifiers[mod_count]; mod_count++);
+ }
+
+ __dump_use_case(verb, devices, dev_count, modifiers, mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("> UCM requested %s", dump_str);
+
+ if (old_verb && streq(verb, old_verb)) {
+ AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
+
+ if (old_dev_count > 0) {
+ dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
+ for (i = 0; i < old_dev_count; i++) {
+ dis_dev_list[i] = NULL;
+ }
+ }
+ if (dev_count > 0) {
+ ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
+ for (i = 0; i < dev_count; i++) {
+ ena_dev_list[i] = NULL;
+ }
+ }
+ if (old_mod_count > 0) {
+ dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
+ for (i = 0; i < old_mod_count; i++) {
+ dis_mod_list[i] = NULL;
+ }
+ }
+ if (mod_count > 0) {
+ ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
+ for (i = 0; i < mod_count; i++) {
+ ena_mod_list[i] = NULL;
+ }
+ }
+
+ /* update disable modifiers list which are not present in new modifier list */
+ for (i = 0; i < old_mod_count; i++) {
+ int need_disable_mod = 1;
+
+ for (j = 0; j < mod_count; j++) {
+ if (streq(old_mod_list[i], modifiers[j])) {
+ need_disable_mod = 0;
+ break;
+ }
+ }
+ if (need_disable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ dis_mod_list[dis_mod_count++] = old_mod_list[i];
+ }
+ }
+
+ /* update disable devices list which are not present in new device list */
+ for (i = 0; i < old_dev_count; i++) {
+ int need_disable_dev = 1;
+
+ for (j = 0; j < dev_count; j++) {
+ if (streq(old_dev_list[i], devices[j])) {
+ need_disable_dev = 0;
+ break;
+ }
+ }
+ if (need_disable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ dis_dev_list[dis_dev_count++] = old_dev_list[i];
+ }
+ }
+
+ /* update enable devices list which are not present in old device list */
+ for (i = 0; i < dev_count; i++) {
+ int need_enable_dev = 1;
+
+ for (j = 0; j < old_dev_count; j++) {
+ if (streq(devices[i], old_dev_list[j])) {
+ need_enable_dev = 0;
+ break;
+ }
+ }
+ if (need_enable_dev) {
+ if (is_dev_changed == 0)
+ is_dev_changed = 1;
+ ena_dev_list[ena_dev_count++] = devices[i];
+ }
+ }
+
+ /* update enable modifiers list which are not present in old modifier list */
+ for (i = 0; i < mod_count; i++) {
+ int need_enable_mod = 1;
+
+ for (j = 0; j < old_mod_count; j++) {
+ if (streq(modifiers[i], old_mod_list[j])) {
+ need_enable_mod = 0;
+ break;
+ }
+ }
+ if (need_enable_mod) {
+ if (is_mod_changed == 0)
+ is_mod_changed = 1;
+ ena_mod_list[ena_mod_count++] = modifiers[i];
+ }
+ }
+
+ /* disable modifiers */
+ for (i = 0; i < dis_mod_count; i++) {
+ AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
+ if (snd_use_case_set(am->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
+ }
+
+ /* disable devices */
+ for (i = 0; i < dis_dev_count; i++) {
+ AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
+ if (snd_use_case_set(am->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
+ }
+
+ /* enable devices */
+ for (i = 0; i < ena_dev_count; i++) {
+ AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
+ if (snd_use_case_set(am->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
+ }
+
+ /* enable modifiers */
+ for (i = 0; i < ena_mod_count; i++) {
+ AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
+ if (snd_use_case_set(am->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
+ AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
+ }
+ } else {
+ is_verb_changed = 1;
+
+ AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
+ /* set new verb */
+ if (snd_use_case_set(am->ucm.uc_mgr, "_verb", verb) < 0) {
+ AUDIO_LOG_ERROR("Setting verb %s failed", verb);
+ audio_ret = AUDIO_ERR_UNDEFINED;
+ goto exit;
+ }
+ /* enable devices */
+ for (i = 0; i < dev_count; i++) {
+ AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
+ if(snd_use_case_set(am->ucm.uc_mgr, "_enadev", devices[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
+ }
+ /* enable modifiers */
+ for (i = 0; i < mod_count; i++) {
+ AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
+ if(snd_use_case_set(am->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
+ AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
+ }
+ }
+
+exit:
+ if (old_verb)
+ free((void *)old_verb);
+ if (old_dev_list)
+ snd_use_case_free_list(old_dev_list, old_dev_count);
+ if (old_mod_list)
+ snd_use_case_free_list(old_mod_list, old_mod_count);
+ if (dis_dev_list)
+ free((void *)dis_dev_list);
+ if (ena_dev_list)
+ free((void *)ena_dev_list);
+ if (dis_mod_list)
+ free((void *)dis_mod_list);
+ if (ena_mod_list)
+ free((void *)ena_mod_list);
+
+ if (is_verb_changed == 1 || is_dev_changed == 1 || is_mod_changed == 1) {
+ const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
+ int new_dev_count = 0, new_mod_count = 0;
+
+ snd_use_case_get(am->ucm.uc_mgr, "_verb", &new_verb);
+ new_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &new_dev_list);
+ new_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &new_mod_list);
+ __dump_use_case(new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count, &dump_str[0]);
+ AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
+
+ if (new_verb)
+ free((void *)new_verb);
+ if (new_dev_list)
+ snd_use_case_free_list(new_dev_list, new_dev_count);
+ if (new_mod_list)
+ snd_use_case_free_list(new_mod_list, new_mod_count);
+ }
+
+ return audio_ret;
+}
+
+
+audio_return_t _audio_ucm_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
index f624ded..5b2477d 100644..100755
--- a/tizen-audio-util.c
+++ b/tizen-audio-util.c
@@ -3,8 +3,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -42,6 +40,8 @@ audio_return_t _audio_util_deinit (audio_mgr_t *am)
return AUDIO_RET_OK;
}
+#ifdef __MIXER_PARAM_DUMP
+
static void __dump_mixer_param(char *dump, long *param, int size)
{
int i, len;
@@ -59,60 +59,299 @@ static void __dump_mixer_param(char *dump, long *param, int size)
*dump = '\0';
}
-audio_return_t _audio_mixer_control_set_param(audio_mgr_t *am, const char* ctl_name, struct snd_ctl_elem_value* param, int size)
+#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)
{
- audio_return_t ret = AUDIO_RET_USE_HW_CONTROL;
- char dump_str[AUDIO_DUMP_STR_LEN];
+ 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));
- AUDIO_LOG_DEBUG("mixer_ctl_set_param %s=%s success", ctl_name, dump_str);
+ 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
-exit:
- pthread_mutex_unlock(&(am->mixer.mutex));
+ 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);
- return ret;
+ 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;
}
-audio_return_t _audio_mixer_control_get_value(audio_mgr_t *am, const char *ctl_name, int *val)
-{
- audio_return_t ret = AUDIO_RET_USE_HW_CONTROL;
+ 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;
+ }
- pthread_mutex_lock(&(am->mixer.mutex));
+ snd_ctl_close(handle);
- AUDIO_LOG_DEBUG("mixer_ctl_get %s=%d success", ctl_name, *val);
+#ifdef AUDIO_DEBUG
+ AUDIO_LOG_INFO("get mixer(%s) = %d success", ctl_name, *val);
+#endif
-exit:
pthread_mutex_unlock(&(am->mixer.mutex));
+ return AUDIO_RET_USE_HW_CONTROL;
- return ret;
+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)
{
- audio_return_t ret = AUDIO_RET_USE_HW_CONTROL;
+ 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));
- AUDIO_LOG_DEBUG("set_mixer %s=%d success", ctl_name, val);
+ 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);
-exit:
pthread_mutex_unlock(&(am->mixer.mutex));
+ return AUDIO_RET_USE_HW_CONTROL;
- return ret;
+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)
{
- audio_return_t ret = AUDIO_RET_USE_HW_CONTROL;
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
- pthread_mutex_lock(&(am->mixer.mutex));
- AUDIO_LOG_DEBUG("set_mixer %s=%s success", ctl_name, value);
+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;
+}
-exit:
- pthread_mutex_unlock(&(am->mixer.mutex));
- return ret;
+/* 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
index 6e1c3ce..db1638a 100644..100755
--- a/tizen-audio.c
+++ b/tizen-audio.c
@@ -3,8 +3,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -30,7 +28,7 @@ int audio_get_revision (void)
return AUDIO_REVISION;
}
-audio_return_t audio_init (void **userdata)
+audio_return_t audio_init (void **userdata, void *platform_data)
{
audio_mgr_t *am;
audio_return_t ret = AUDIO_RET_OK;
@@ -39,6 +37,8 @@ audio_return_t audio_init (void **userdata)
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;
@@ -51,6 +51,10 @@ audio_return_t audio_init (void **userdata)
AUDIO_LOG_ERROR("stream init failed");
goto error_exit;
}
+ if (AUDIO_IS_ERROR((ret = _audio_ucm_init(am)))) {
+ AUDIO_LOG_ERROR("ucm init failed");
+ goto error_exit;
+ }
if (AUDIO_IS_ERROR((ret = _audio_util_init(am)))) {
AUDIO_LOG_ERROR("mixer init failed");
goto error_exit;
@@ -74,6 +78,7 @@ audio_return_t audio_deinit (void **userdata)
_audio_session_deinit(am);
_audio_device_deinit(am);
_audio_stream_deinit(am);
+ _audio_ucm_deinit(am);
_audio_util_deinit(am);
free(am);
*userdata = NULL;
@@ -82,32 +87,19 @@ audio_return_t audio_deinit (void **userdata)
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_device_deinit(am);
_audio_stream_deinit(am);
- _audio_util_deinit(am);
- 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_util_init(am)))) {
- AUDIO_LOG_ERROR("mixer init failed");
- goto error_exit;
- }
}
return AUDIO_RET_OK;
@@ -119,3 +111,15 @@ error_exit:
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
index 8cbe5ca..e29a08c 100644..100755
--- a/tizen-audio.h
+++ b/tizen-audio.h
@@ -6,8 +6,6 @@
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Hyunseok Lee <hs7388.lee@samsung.com>
- *
* 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
@@ -39,6 +37,7 @@ typedef enum audio_return {
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 ;
@@ -63,15 +62,21 @@ typedef enum audio_subsession {
AUDIO_SUBSESSION_VOICE,
AUDIO_SUBSESSION_RINGTONE,
AUDIO_SUBSESSION_MEDIA,
- AUDIO_SUBSESSION_VR_INIT,
+ AUDIO_SUBSESSION_INIT,
AUDIO_SUBSESSION_VR_NORMAL,
AUDIO_SUBSESSION_VR_DRIVE,
AUDIO_SUBSESSION_STEREO_REC,
- AUDIO_SUBSESSION_AM_PLAY,
- AUDIO_SUBSESSION_AM_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 {
@@ -108,12 +113,14 @@ typedef enum audio_device_out {
typedef enum audio_route_flag {
AUDIO_ROUTE_FLAG_NONE = 0,
- AUDIO_ROUTE_FLAG_DUAL_OUT = 0x00000001,
- AUDIO_ROUTE_FLAG_NOISE_REDUCTION = 0x00000002,
- AUDIO_ROUTE_FLAG_EXTRA_VOL = 0x00000004,
- AUDIO_ROUTE_FLAG_WB = 0x00000008,
- AUDIO_ROUTE_FLAG_SVOICE_COMMAND = 0x00010000,
- AUDIO_ROUTE_FLAG_SVOICE_WAKEUP = 0x00020000,
+ 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 {
@@ -122,7 +129,33 @@ typedef enum audio_device_api {
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;
@@ -134,6 +167,9 @@ typedef struct audio_device_bluz_info {
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;
@@ -151,9 +187,8 @@ typedef enum audio_volume {
AUDIO_VOLUME_TYPE_MEDIA, /**< Media volume type */
AUDIO_VOLUME_TYPE_CALL, /**< Call volume type */
AUDIO_VOLUME_TYPE_VOIP, /**< VOIP volume type */
- AUDIO_VOLUME_TYPE_SVOICE, /**< SVOICE volume type */
+ AUDIO_VOLUME_TYPE_VOICE, /**< Voice volume type */
AUDIO_VOLUME_TYPE_FIXED, /**< Volume type for fixed acoustic level */
- AUDIO_VOLUME_TYPE_EXT_JAVA, /**< External system volume for Java */
AUDIO_VOLUME_TYPE_MAX, /**< Volume type count */
} audio_volume_t;
@@ -172,25 +207,8 @@ typedef enum audio_gain {
AUDIO_GAIN_TYPE_MAX,
} audio_gain_t;
-#if 0 // TODO : need to consider */
-typedef enum audio_volume_format {
- AUDIO_VOLUME_FORMAT_LINEAR, /**< Linear format (double) */
- AUDIO_VOLUME_FORMAT_DECIBEL, /**< Decibel format (double) */
- AUDIO_VOLUME_FORMAT_PA, /**< PulseAudio format (pa_volume_t) */
-} audio_volume_format_t;
-
-typedef struct audio_volume_value {
- audio_volume_format format;
- union {
- double linear;
- double decibel;
- uint32_t pa;
- } value;
-} audio_volume_value_t;
-#endif
-
typedef struct audio_stream_info {
- const char *name;
+ char *name;
uint32_t samplerate;
uint8_t channels;
uint32_t volume_type;
@@ -205,18 +223,52 @@ typedef struct audio_info {
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_interface_t;
+
int audio_get_revision (void);
-audio_return_t audio_init (void **userdata);
+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);
+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);
#endif