- add tizen-audio-impl.h and tizen-audio-impl-xxx.c for implemetation layer that could be code variation as per HW
- rename files
- remove unused functions
- rename functions according to rules("__" prefix for static functions)
[Version] 0.1.10
[Profile] Mobile
[Issue Type] Refactoring
Change-Id: Ib222389161b53efc58832384b1a86542f1de42df
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
lib_LTLIBRARIES = libtizen-audio.la
libtizen_audio_la_SOURCES = tizen-audio.c \
- tizen-audio-device.c \
tizen-audio-volume.c \
- tizen-audio-ucm.c \
+ tizen-audio-routing.c \
+ tizen-audio-stream.c \
+ tizen-audio-pcm.c \
tizen-audio-modem.c \
tizen-audio-comm.c \
- tizen-audio-util.c
+ tizen-audio-util.c \
+ tizen-audio-impl-pcm.c \
+ tizen-audio-impl-ucm.c \
+ tizen-audio-impl-ctrl.c
libtizen_audio_la_LDFLAGS = $(AM_LDFLAGS) -disable-static -avoid-version
libtizen_audio_la_LIBADD = $(AM_LDADD) $(ASOUNDLIB_LIBS) $(VCONF_LIBS) $(DLOG_LIBS) $(INIPARSER_LIBS) $(EXPAT_LIBS)
libtizen_audio_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS) $(VCONF_CFLAGS) $(DLOG_CFLAGS) $(INIPARSER_CFLAGS) $(EXPAT_CFLAGS) -DUSE_DLOG
Name: audio-hal-sc7727
Summary: TIZEN Audio HAL for SC7727
-Version: 0.1.9
+Version: 0.1.10
Release: 0
Group: System/Libraries
License: Apache-2.0
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "tizen-audio-internal.h"
-audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(name, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_DEBUG("send message : name(%s), value(%d)", name, value);
- if (ah->comm.msg_cb) {
- ah->comm.msg_cb(name, value, ah->comm.user_data);
- }
-
- return audio_ret;
-}
-
-audio_return_t _audio_comm_set_message_callback(audio_hal_t *ah, message_cb callback, void *user_data)
+static audio_return_t __set_message_callback(audio_hal_t *ah, message_cb callback, void *user_data)
{
audio_return_t audio_ret = AUDIO_RET_OK;
return audio_ret;
}
-audio_return_t _audio_comm_unset_message_callback(audio_hal_t *ah)
+static audio_return_t __unset_message_callback(audio_hal_t *ah)
{
audio_return_t audio_ret = AUDIO_RET_OK;
return audio_ret;
}
+
+audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(name, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_DEBUG("send message : name(%s), value(%d)", name, value);
+ if (ah->comm.msg_cb) {
+ ah->comm.msg_cb(name, value, ah->comm.user_data);
+ }
+
+ return audio_ret;
+}
+
+audio_return_t audio_add_message_cb(void *audio_handle, message_cb callback, void *user_data)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+ /* NOTE: Management of several callbacks could be implemented.
+ But we do not care of it for now.*/
+ ret = __set_message_callback((audio_hal_t *)audio_handle, callback, user_data);
+
+ return ret;
+}
+
+audio_return_t audio_remove_message_cb(void *audio_handle, message_cb callback)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
+
+ ret = __unset_message_callback((audio_hal_t *)audio_handle);
+
+ return ret;
+}
\ No newline at end of file
+++ /dev/null
-/*
- * 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"
-
-#ifndef __USE_TINYALSA__
-/* FIXME : To avoid build warning... */
-int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
-#endif
-
-/* #define DEBUG_TIMING */
-
-static device_type_t outDeviceTypes[] = {
- { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
- { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
- { AUDIO_DEVICE_OUT_JACK, "Headphones" },
- { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
- { 0, 0 },
-};
-
-static device_type_t inDeviceTypes[] = {
- { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
- { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
- { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
- { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
- { 0, 0 },
-};
-
-static const char* mode_to_verb_str[] = {
- AUDIO_USE_CASE_VERB_HIFI,
- AUDIO_USE_CASE_VERB_VOICECALL,
- AUDIO_USE_CASE_VERB_VIDEOCALL,
- AUDIO_USE_CASE_VERB_VOIP,
-};
-
-static int _voice_pcm_open(audio_hal_t *ah);
-static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
-static void _reset_pcm_devices(audio_hal_t *ah);
-static void _reset_voice_devices_info(audio_hal_t *ah);
-
-static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t direction)
-{
- uint32_t device = 0;
-
- if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
- device = AUDIO_DEVICE_OUT_SPEAKER;
- } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
- device = AUDIO_DEVICE_OUT_RECEIVER;
- } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
- device = AUDIO_DEVICE_OUT_JACK;
- } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
- device = AUDIO_DEVICE_OUT_BT_SCO;
- } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
- device = AUDIO_DEVICE_IN_MAIN_MIC;
- /* To Do : SUB_MIC */
- } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
- device = AUDIO_DEVICE_IN_JACK;
- } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
- device = AUDIO_DEVICE_IN_BT_SCO;
- } else {
- device = AUDIO_DEVICE_NONE;
- }
- AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
- return device;
-}
-
-static audio_return_t set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- uint32_t new_device = 0;
- const char *active_devices[MAX_DEVICES] = {NULL,};
- int i = 0, j = 0, dev_idx = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
-
- if (num_of_devices > MAX_DEVICES) {
- num_of_devices = MAX_DEVICES;
- AUDIO_LOG_ERROR("error: num_of_devices");
- return AUDIO_ERR_PARAMETER;
- }
-
- if (devices[0].direction == AUDIO_DIRECTION_OUT) {
- ah->device.active_out &= 0x0;
- if (ah->device.active_in) {
- /* check the active in devices */
- for (j = 0; j < inDeviceTypes[j].type; j++) {
- if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
- active_devices[dev_idx++] = inDeviceTypes[j].name;
- }
- }
- } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
- ah->device.active_in &= 0x0;
- if (ah->device.active_out) {
- /* check the active out devices */
- for (j = 0; j < outDeviceTypes[j].type; j++) {
- if (ah->device.active_out & outDeviceTypes[j].type)
- active_devices[dev_idx++] = outDeviceTypes[j].name;
- }
- }
- }
-
- for (i = 0; i < num_of_devices; i++) {
- new_device = convert_device_string_to_enum(devices[i].type, devices[i].direction);
- if (new_device & AUDIO_DEVICE_IN) {
- for (j = 0; j < inDeviceTypes[j].type; j++) {
- if (new_device == inDeviceTypes[j].type) {
- active_devices[dev_idx++] = inDeviceTypes[j].name;
- ah->device.active_in |= new_device;
- }
- }
- } else {
- for (j = 0; j < outDeviceTypes[j].type; j++) {
- if (new_device == outDeviceTypes[j].type) {
- active_devices[dev_idx++] = outDeviceTypes[j].name;
- ah->device.active_out |= new_device;
- }
- }
- }
- }
-
- if (active_devices[0] == NULL) {
- AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
- return AUDIO_ERR_PARAMETER;
- }
-
- audio_ret = _audio_ucm_set_devices(ah, verb, active_devices);
- if (audio_ret)
- AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
-
- return audio_ret;
-}
-
-audio_return_t _audio_device_init(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- ah->device.active_in = 0x0;
- ah->device.active_out = 0x0;
- ah->device.pcm_in = NULL;
- ah->device.pcm_out = NULL;
- ah->device.mode = VERB_NORMAL;
- pthread_mutex_init(&ah->device.pcm_lock, NULL);
- pthread_mutex_init(&ah->device.device_lock, NULL);
- pthread_cond_init(&ah->device.device_cond, NULL);
- ah->device.pcm_count = 0;
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t _audio_device_deinit(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- pthread_mutex_destroy(&ah->device.pcm_lock);
- pthread_mutex_destroy(&ah->device.device_lock);
- pthread_cond_destroy(&ah->device.device_cond);
- return AUDIO_RET_OK;
-}
-
-static audio_return_t _update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- device_info_t *devices = NULL;
- const char *verb = mode_to_verb_str[VERB_NORMAL];
-#if 0 /* Disable setting modifiers, because driver does not support it yet */
- int mod_idx = 0;
- const char *modifiers[MAX_MODIFIERS] = {NULL,};
-#endif
-
- if (ah->modem.is_connected) {
- AUDIO_LOG_INFO("modem is connected, skip verb[%s]", verb);
- return audio_ret;
- }
-
- if (ah->device.mode != VERB_NORMAL) {
- if (ah->device.mode == VERB_VOICECALL) {
- _reset_voice_devices_info(ah);
- COND_SIGNAL(ah->device.device_cond, "device_cond");
- }
- _reset_pcm_devices(ah);
- ah->device.mode = VERB_NORMAL;
- }
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
-
- devices = route_info->device_infos;
-
- AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
-
- audio_ret = set_devices(ah, verb, devices, route_info->num_of_devices);
- if (audio_ret) {
- AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
- return audio_ret;
- }
- ah->device.mode = VERB_NORMAL;
-
-#if 0 /* Disable setting modifiers, because driver does not support it yet */
- /* Set modifiers */
- if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
- } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
- if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
- else
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
- } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
- if (ah->device.active_out)
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
- } else {
- if (ah->device.active_in)
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
- else
- modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
- }
- audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
-#endif
- return audio_ret;
-}
-
-static audio_return_t _update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- const char *verb = mode_to_verb_str[VERB_VOICECALL];
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- /* if both params are 0, return error for invalid state,
- * this error would be used to tizen-audio-modem.c */
- AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
- AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("update_route_voicecall++");
-
- audio_ret = set_devices(ah, verb, devices, num_of_devices);
- if (audio_ret) {
- AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
- return audio_ret;
- }
-
- if (ah->device.mode != VERB_VOICECALL) {
- _voice_pcm_open(ah);
- ah->device.mode = VERB_VOICECALL;
- /* FIXME. Get network info and configure rate in pcm device */
- }
-
- return audio_ret;
-}
-
-static audio_return_t _update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- const char *verb = mode_to_verb_str[VERB_NORMAL];
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("update_route_voip++");
-
- audio_ret = set_devices(ah, verb, devices, num_of_devices);
- if (audio_ret) {
- AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
- return audio_ret;
- }
- /* FIXME. If necessary, set VERB_VOIP */
- ah->device.mode = VERB_NORMAL;
-
- /* TO DO: Set modifiers */
- return audio_ret;
-}
-
-static audio_return_t _update_route_reset(audio_hal_t *ah, uint32_t direction)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- const char *active_devices[MAX_DEVICES] = {NULL,};
- int i = 0, dev_idx = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
-
- if (direction == AUDIO_DIRECTION_OUT) {
- ah->device.active_out &= 0x0;
- if (ah->device.active_in) {
- /* check the active in devices */
- for (i = 0; i < inDeviceTypes[i].type; i++) {
- if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
- active_devices[dev_idx++] = inDeviceTypes[i].name;
- AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
- }
- }
- }
- } else {
- ah->device.active_in &= 0x0;
- if (ah->device.active_out) {
- /* check the active out devices */
- for (i = 0; i < outDeviceTypes[i].type; i++) {
- if (ah->device.active_out & outDeviceTypes[i].type) {
- active_devices[dev_idx++] = outDeviceTypes[i].name;
- AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
- }
- }
- }
- }
- if (ah->device.mode == VERB_VOICECALL) {
- _voice_pcm_close(ah, direction);
- if (!ah->device.active_in && !ah->device.active_out)
- ah->device.mode = VERB_NORMAL;
- _reset_voice_devices_info(ah);
- COND_SIGNAL(ah->device.device_cond, "device_cond");
- }
-
- if (active_devices[0] == NULL) {
- AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
- return AUDIO_RET_OK;
- }
-
- audio_ret = _audio_ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices);
- if (audio_ret)
- AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
-
- return audio_ret;
-}
-
-audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- audio_hal_t *ah = (audio_hal_t *)audio_handle;
- device_info_t *devices = NULL;
- uint32_t prev_size;
- int32_t i;
- int32_t j;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("role:%s", info->role);
-
- devices = info->device_infos;
-
- if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
- if (!ah->modem.is_connected) {
- if (info->num_of_devices) {
- if (!ah->device.num_of_call_devices) {
- if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
- memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
- ah->device.num_of_call_devices = info->num_of_devices;
- } else {
- AUDIO_LOG_ERROR("failed to calloc");
- audio_ret = AUDIO_ERR_RESOURCE;
- goto ERROR;
- }
- } else if (ah->device.num_of_call_devices) {
- prev_size = ah->device.num_of_call_devices;
- if (prev_size == 2) {
- /* There's a chance to be requested to change routing from user
- * though two devices(for input/output) has already been set for call-voice routing.
- * In this case, exchange an old device for a new device if it's direction is same as an old one's. */
- for (i = 0; i < prev_size; i++) {
- for (j = 0; j < info->num_of_devices; j++) {
- if (devices[j].direction == ah->device.init_call_devices[i].direction &&
- devices[j].id != ah->device.init_call_devices[i].id)
- memcpy(&ah->device.init_call_devices[i], &devices[j], sizeof(device_info_t));
- }
- }
- } else if (prev_size < 2) {
- /* A device has already been added for call-voice routing,
- * and now it is about to add a new device(input or output device). */
- ah->device.num_of_call_devices += info->num_of_devices;
- if ((ah->device.init_call_devices = (device_info_t*)realloc(ah->device.init_call_devices, sizeof(device_info_t)*ah->device.num_of_call_devices))) {
- memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
- } else {
- AUDIO_LOG_ERROR("failed to realloc");
- audio_ret = AUDIO_ERR_RESOURCE;
- goto ERROR;
- }
- } else {
- AUDIO_LOG_ERROR("invaild previous num. of call devices");
- audio_ret = AUDIO_ERR_INTERNAL;
- goto ERROR;
- }
- }
- } else {
- AUDIO_LOG_ERROR("failed to do route for call-voice, num_of_devices is 0");
- audio_ret = AUDIO_ERR_PARAMETER;
- goto ERROR;
- }
- AUDIO_LOG_INFO("modem is not ready, skip...");
- } else {
- audio_ret = _update_route_voicecall(ah, devices, info->num_of_devices);
- if (AUDIO_IS_ERROR(audio_ret)) {
- AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
- }
- COND_SIGNAL(ah->device.device_cond, "device_cond");
- }
- } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
- audio_ret = _update_route_voip(ah, devices, info->num_of_devices);
- if (AUDIO_IS_ERROR(audio_ret)) {
- AUDIO_LOG_WARN("set voip route return 0x%x", audio_ret);
- }
- } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
- audio_ret = _update_route_reset(ah, devices->direction);
- if (AUDIO_IS_ERROR(audio_ret)) {
- AUDIO_LOG_WARN("set reset return 0x%x", audio_ret);
- }
- } else {
- /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
- audio_ret = _update_route_ap_playback_capture(ah, info);
- if (AUDIO_IS_ERROR(audio_ret)) {
- AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
- }
- }
-
-ERROR:
- return audio_ret;
-}
-
-audio_return_t audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- audio_hal_t *ah = (audio_hal_t *)audio_handle;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
-
- return audio_ret;
-}
-
-audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
-{
- audio_return_t audio_ret = AUDIO_RET_OK;
- audio_hal_t *ah = (audio_hal_t *)audio_handle;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
-
- return audio_ret;
-}
-
-static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
-{
- snd_pcm_hw_params_t *params = NULL;
- int err = 0;
- unsigned int val = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
-
- /* Skip parameter setting to null device. */
- if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
- return AUDIO_ERR_IOCTL;
-
- /* Allocate a hardware parameters object. */
- snd_pcm_hw_params_alloca(¶ms);
-
- /* 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, 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;
-}
-
-static int _voice_pcm_open(audio_hal_t *ah)
-{
- int err, ret = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("open voice pcm handles");
-
- /* Get playback voice-pcm from ucm conf. Open and set-params */
- if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
- return AUDIO_ERR_IOCTL;
- }
- ret = __voice_pcm_set_params(ah, ah->device.pcm_out);
-
- AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
-
- /* Get capture voice-pcm from ucm conf. Open and set-params */
- if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
- return AUDIO_ERR_IOCTL;
- }
- ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
- AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
-
- return ret;
-}
-
-static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("close voice pcm handles");
-
- if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
- audio_pcm_close((void *)ah, ah->device.pcm_out);
- ah->device.pcm_out = NULL;
- AUDIO_LOG_INFO("voice pcm_out handle close success");
- } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
- audio_pcm_close((void *)ah, ah->device.pcm_in);
- ah->device.pcm_in = NULL;
- AUDIO_LOG_INFO("voice pcm_in handle close success");
- }
-
- return AUDIO_RET_OK;
-}
-
-static void _reset_pcm_devices(audio_hal_t *ah)
-{
- AUDIO_RETURN_IF_FAIL(ah);
-
- if (ah->device.pcm_out) {
- audio_pcm_close((void *)ah, ah->device.pcm_out);
- ah->device.pcm_out = NULL;
- AUDIO_LOG_INFO("pcm_out handle close success");
- }
- if (ah->device.pcm_in) {
- audio_pcm_close((void *)ah, ah->device.pcm_in);
- ah->device.pcm_in = NULL;
- AUDIO_LOG_INFO("pcm_in handle close success");
- }
-
- return;
-}
-
-static void _reset_voice_devices_info(audio_hal_t *ah)
-{
- AUDIO_RETURN_IF_FAIL(ah);
-
- AUDIO_LOG_INFO("reset voice device info");
- if (ah->device.init_call_devices) {
- free(ah->device.init_call_devices);
- ah->device.init_call_devices = NULL;
- ah->device.num_of_call_devices = 0;
- }
-
- return;
-}
-
-#ifdef __USE_TINYALSA__
-static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t period_size, size_t period_count, uint32_t direction)
-{
- struct pcm *pcm = NULL;
- struct pcm_config config;
-
- AUDIO_RETURN_NULL_IF_FAIL(ss);
-
- config.channels = ss->channels;
- config.rate = ss->rate;
- config.period_size = period_size;
- config.period_count = period_count;
- config.format = ss->format;
- config.start_threshold = period_size;
- config.stop_threshold = 0xFFFFFFFF;
- config.silence_threshold = 0;
-
- AUDIO_LOG_INFO("direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d", direction, ss->channels, ss->rate, ss->format, period_size, period_count);
-
- pcm = pcm_open((direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_CARD_ID : CAPTURE_CARD_ID,
- (direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_PCM_DEVICE_ID : CAPTURE_PCM_DEVICE_ID,
- (direction == AUDIO_DIRECTION_OUT) ? PCM_OUT : PCM_IN,
- &config);
- if (!pcm || !pcm_is_ready(pcm)) {
- AUDIO_LOG_ERROR("Unable to open device (%s)", pcm_get_error(pcm));
- pcm_close(pcm);
- return NULL;
- }
-
- return pcm;
-}
-#endif
-
-audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
-{
- return _update_route_voicecall(ah, devices, num_of_devices);
-}
-
-audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
-{
-#ifdef __USE_TINYALSA__
- audio_hal_t *ah;
- audio_pcm_sample_spec_t *ss;
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
-
- ah = (audio_hal_t *)audio_handle;
- ss = (audio_pcm_sample_spec_t *)sample_spec;
- ss->format = _convert_format((audio_sample_format_t)ss->format);
-
- *pcm_handle = __tinyalsa_open_device(ss, (size_t)period_size, (size_t)periods, direction);
- if (*pcm_handle == NULL) {
- AUDIO_LOG_ERROR("Error opening PCM device");
- return AUDIO_ERR_RESOURCE;
- }
-
- if ((err = pcm_prepare((struct pcm *)*pcm_handle)) != 0) {
- AUDIO_LOG_ERROR("Error prepare PCM device : %d", err);
- }
-
- ah->device.pcm_count++;
- AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
-#else /* alsa-lib */
- audio_hal_t *ah;
- int err, mode;
- char *device_name = NULL;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
-
- ah = (audio_hal_t *)audio_handle;
- mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
-
- if (direction == AUDIO_DIRECTION_OUT)
- device_name = PLAYBACK_PCM_DEVICE;
- else if (direction == AUDIO_DIRECTION_IN)
- device_name = CAPTURE_PCM_DEVICE;
- else {
- AUDIO_LOG_ERROR("Error get device_name, direction : %d", direction);
- return AUDIO_ERR_RESOURCE;
- }
-
- if ((err = snd_pcm_open((snd_pcm_t **)pcm_handle, device_name, (direction == AUDIO_DIRECTION_OUT) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, mode)) < 0) {
- AUDIO_LOG_ERROR("Error opening PCM device %s : %s", device_name, snd_strerror(err));
- return AUDIO_ERR_RESOURCE;
- }
-
- if ((err = audio_pcm_set_params(audio_handle, *pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
- AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", err);
- return err;
- }
-
- ah->device.pcm_count++;
- AUDIO_LOG_INFO("Opening PCM handle 0x%x, PCM device %s", *pcm_handle, device_name);
-#endif
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_start(void *audio_handle, void *pcm_handle)
-{
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
-#ifdef __USE_TINYALSA__
- if ((err = pcm_start(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error starting PCM handle : %d", err);
- return AUDIO_ERR_RESOURCE;
- }
-#else /* alsa-lib */
- if ((err = snd_pcm_start(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error starting PCM handle : %s", snd_strerror(err));
- return AUDIO_ERR_RESOURCE;
- }
-#endif
-
- AUDIO_LOG_INFO("PCM handle 0x%x start", pcm_handle);
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
-{
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
-#ifdef __USE_TINYALSA__
- if ((err = pcm_stop(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error stopping PCM handle : %d", err);
- return AUDIO_ERR_RESOURCE;
- }
-#else /* alsa-lib */
- if ((err = snd_pcm_drop(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error stopping PCM handle : %s", snd_strerror(err));
- return AUDIO_ERR_RESOURCE;
- }
-#endif
-
- AUDIO_LOG_INFO("PCM handle 0x%x stop", pcm_handle);
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
-{
- audio_hal_t *ah = (audio_hal_t *)audio_handle;
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
-
-#ifdef __USE_TINYALSA__
- if ((err = pcm_close(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error closing PCM handle : %d", err);
- return AUDIO_ERR_RESOURCE;
- }
-#else /* alsa-lib */
- if ((err = snd_pcm_close(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
- return AUDIO_ERR_RESOURCE;
- }
-#endif
-
- pcm_handle = NULL;
- ah->device.pcm_count--;
- AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
-{
-#ifdef __USE_TINYALSA__
- struct timespec tspec;
- unsigned int frames_avail = 0;
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
-
- err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
- if (err < 0) {
- AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle 0x%x : %d", pcm_handle, err);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("avail = %d", frames_avail);
-#endif
-
- *avail = (uint32_t)frames_avail;
-#else /* alsa-lib */
- snd_pcm_sframes_t frames_avail;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
-
- if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Could not get avail at PCM handle 0x%x : %d", pcm_handle, frames_avail);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("avail = %d", frames_avail);
-#endif
-
- *avail = (uint32_t)frames_avail;
-#endif
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
-{
-#ifdef __USE_TINYALSA__
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- err = pcm_write(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
- if (err < 0) {
- AUDIO_LOG_ERROR("Failed to write pcm : %d", err);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("audio_pcm_write = %d", frames);
-#endif
-#else /* alsa-lib */
- snd_pcm_sframes_t frames_written;
-
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- frames_written = snd_pcm_writei(pcm_handle, buffer, (snd_pcm_uframes_t) frames);
- if (frames_written < 0) {
- AUDIO_LOG_ERROR("Failed to write pcm : %d", frames_written);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("audio_pcm_write = (%d / %d)", frames_written, frames);
-#endif
-#endif
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
-{
-#ifdef __USE_TINYALSA__
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- err = pcm_read(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
- if (err < 0) {
- AUDIO_LOG_ERROR("Failed to read pcm : %d", err);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("audio_pcm_read = %d", frames);
-#endif
-#else /* alsa-lib */
- snd_pcm_sframes_t frames_read;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
- if (frames_read < 0) {
- AUDIO_LOG_ERROR("Failed to read pcm : %d", frames_read);
- return AUDIO_ERR_IOCTL;
- }
-
-#ifdef DEBUG_TIMING
- AUDIO_LOG_DEBUG("audio_pcm_read = (%d / %d)", frames_read, frames);
-#endif
-#endif
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
-{
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
- /* we use an internal API of the (tiny)alsa library, so it causes warning message during compile */
-#ifdef __USE_TINYALSA__
- *fd = _pcm_poll_descriptor((struct pcm *)pcm_handle);
-#else /* alsa-lib */
- *fd = _snd_pcm_poll_descriptor((snd_pcm_t *)pcm_handle);
-#endif
- return AUDIO_RET_OK;
-}
-
-#ifdef __USE_TINYALSA__
-static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
-{
- if (err > 0)
- err = -err;
- if (err == -EINTR) /* nothing to do, continue */
- return 0;
- if (err == -EPIPE) {
- AUDIO_LOG_INFO("XRUN occurred");
- err = pcm_prepare(pcm);
- if (err < 0) {
- AUDIO_LOG_ERROR("Could not recover from XRUN occurred, prepare failed : %d", err);
- return err;
- }
- return 0;
- }
- if (err == -ESTRPIPE) {
- /* tinyalsa does not support pcm resume, dont't care suspend case */
- AUDIO_LOG_ERROR("Could not recover from suspend : %d", err);
- return err;
- }
- return err;
-}
-#endif
-
-audio_return_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
-{
- int state, err;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
-
- if (revents & POLLERR)
- AUDIO_LOG_DEBUG("Got POLLERR from ALSA");
- if (revents & POLLNVAL)
- AUDIO_LOG_DEBUG("Got POLLNVAL from ALSA");
- if (revents & POLLHUP)
- AUDIO_LOG_DEBUG("Got POLLHUP from ALSA");
- if (revents & POLLPRI)
- AUDIO_LOG_DEBUG("Got POLLPRI from ALSA");
- if (revents & POLLIN)
- AUDIO_LOG_DEBUG("Got POLLIN from ALSA");
- if (revents & POLLOUT)
- AUDIO_LOG_DEBUG("Got POLLOUT from ALSA");
-
-#ifdef __USE_TINYALSA__
- state = pcm_state(pcm_handle);
- AUDIO_LOG_DEBUG("PCM state is %d", state);
-
- switch (state) {
- case PCM_STATE_XRUN:
- if ((err = __tinyalsa_pcm_recover(pcm_handle, -EPIPE)) != 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- break;
-
- case PCM_STATE_SUSPENDED:
- if ((err = __tinyalsa_pcm_recover(pcm_handle, -ESTRPIPE)) != 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- break;
-
- default:
- pcm_stop(pcm_handle);
- if ((err = pcm_prepare(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with pcm_prepare() : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- }
-#else /* alsa-lib */
- state = snd_pcm_state(pcm_handle);
- AUDIO_LOG_DEBUG("PCM state is %s", snd_pcm_state_name(state));
-
- /* Try to recover from this error */
-
- switch (state) {
- case SND_PCM_STATE_XRUN:
- if ((err = snd_pcm_recover(pcm_handle, -EPIPE, 1)) != 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- break;
-
- case SND_PCM_STATE_SUSPENDED:
- if ((err = snd_pcm_recover(pcm_handle, -ESTRPIPE, 1)) != 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- break;
-
- default:
- snd_pcm_drop(pcm_handle);
- if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare() : %d", err);
- return AUDIO_ERR_IOCTL;
- }
- break;
- }
-#endif
-
- AUDIO_LOG_DEBUG("audio_pcm_recover");
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
-{
-#ifdef __USE_TINYALSA__
- audio_pcm_sample_spec_t *ss;
- unsigned int _period_size, _buffer_size, _periods, _format, _rate, _channels;
- unsigned int _start_threshold, _stop_threshold, _silence_threshold;
- struct pcm_config *config;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
- ss = (audio_pcm_sample_spec_t *)*sample_spec;
-
- /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
- _pcm_config(pcm_handle, &config);
-
- *period_size = config->period_size;
- *periods = config->period_count;
- _buffer_size = config->period_size * config->period_count;
- ss->format = config->format;
- ss->rate = config->rate;
- ss->channels = config->channels;
- _start_threshold = config->start_threshold;
- _stop_threshold = config->stop_threshold;
- _silence_threshold = config->silence_threshold;
-
- AUDIO_LOG_DEBUG("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, config->format, config->rate, config->channels, config->period_size, config->period_count, _buffer_size);
-#else /* alsa-lib */
- int err;
- audio_pcm_sample_spec_t *ss;
- int dir;
- snd_pcm_uframes_t _period_size, _buffer_size;
- snd_pcm_format_t _format;
- unsigned int _rate, _channels;
- snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
- unsigned int _periods;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
- ss = (audio_pcm_sample_spec_t *)*sample_spec;
-
- snd_pcm_hw_params_alloca(&hwparams);
- snd_pcm_sw_params_alloca(&swparams);
-
- if ((err = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_current() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
- (err = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0 ||
- (err = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0 ||
- (err = snd_pcm_hw_params_get_format(hwparams, &_format)) < 0 ||
- (err = snd_pcm_hw_params_get_rate(hwparams, &_rate, &dir)) < 0 ||
- (err = snd_pcm_hw_params_get_channels(hwparams, &_channels)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %s", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- *period_size = _period_size;
- *periods = _periods;
- ss->format = _format;
- ss->rate = _rate;
- ss->channels = _channels;
-
- if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params_get_start_threshold(swparams, &_start_threshold)) < 0 ||
- (err = snd_pcm_sw_params_get_stop_threshold(swparams, &_stop_threshold)) < 0 ||
- (err = snd_pcm_sw_params_get_silence_threshold(swparams, &_silence_threshold)) < 0 ||
- (err = snd_pcm_sw_params_get_avail_min(swparams, &_avail_min)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %s", err);
- }
-
- AUDIO_LOG_DEBUG("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size);
-#endif
-
- return AUDIO_RET_OK;
-}
-
-audio_return_t audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
-{
-#ifdef __USE_TINYALSA__
- /* Parameters are only acceptable in pcm_open() function */
- AUDIO_LOG_DEBUG("audio_pcm_set_params");
-#else /* alsa-lib */
- int err;
- audio_pcm_sample_spec_t ss;
- snd_pcm_uframes_t _buffer_size;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
- ss = *(audio_pcm_sample_spec_t *)sample_spec;
-
- snd_pcm_hw_params_alloca(&hwparams);
- snd_pcm_sw_params_alloca(&swparams);
-
- /* Set hw params */
- if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_any() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate_resample() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- ss.format = _convert_format((audio_sample_format_t)ss.format);
- if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, ss.format)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_format() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_period_size(pcm_handle, hwparams, period_size, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size(%u) failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods(%u) failed : %d", periods, err);
- return AUDIO_ERR_PARAMETER;
- }
-
- _buffer_size = period_size * periods;
- if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, _buffer_size)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size(%u) failed : %d", periods * periods, err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
- return AUDIO_ERR_IOCTL;
- }
-
- /* Set sw params */
- if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
- AUDIO_LOG_ERROR("Unable to determine current swparams : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm_handle, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
- AUDIO_LOG_ERROR("Unable to enable time stamping : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xFFFFFFFF)) < 0) {
- AUDIO_LOG_ERROR("Unable to set stop threshold : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, period_size / 2)) < 0) {
- AUDIO_LOG_ERROR("Unable to set start threshold : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, 1024)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
- return AUDIO_ERR_PARAMETER;
- }
-
- if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) {
- AUDIO_LOG_ERROR("Unable to set sw params : %d", err);
- return AUDIO_ERR_IOCTL;
- }
-
- /* Prepare device */
- if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_prepare() failed : %d", err);
- return AUDIO_ERR_IOCTL;
- }
-
- AUDIO_LOG_DEBUG("audio_pcm_set_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, ss.format, ss.rate, ss.channels, period_size, periods, _buffer_size);
-#endif
-
- return AUDIO_RET_OK;
-}
--- /dev/null
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "tizen-audio-internal.h"
+
+#ifdef __MIXER_PARAM_DUMP
+static void __dump_mixer_param(char *dump, long *param, int size)
+{
+ int i, len;
+
+ for (i = 0; i < size; i++) {
+ len = sprintf(dump, "%ld", *param);
+ if (len > 0)
+ dump += len;
+ if (i != size -1) {
+ *dump++ = ',';
+ }
+
+ param++;
+ }
+ *dump = '\0';
+}
+#endif
+
+audio_return_t _control_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_init(&(ah->mixer.mutex), NULL);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _control_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_destroy(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* param, int size)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
+{
+ snd_ctl_t *handle;
+ snd_ctl_elem_value_t *control;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_type_t type;
+
+ int ret = 0, count = 0, i = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, %s\n", snd_strerror(ret));
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_IOCTL;
+ }
+
+ // Get Element Info
+
+ snd_ctl_elem_id_alloca(&id);
+ snd_ctl_elem_info_alloca(&info);
+ snd_ctl_elem_value_alloca(&control);
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl_name);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if (snd_ctl_elem_info(handle, info) < 0) {
+ AUDIO_LOG_ERROR("Cannot find control element: %s\n", ctl_name);
+ goto close;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ type = snd_ctl_elem_info_get_type(info);
+ count = snd_ctl_elem_info_get_count(info);
+
+ snd_ctl_elem_value_set_id(control, id);
+
+ if (snd_ctl_elem_read(handle, control) < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_elem_read failed \n");
+ goto close;
+}
+
+ switch (type) {
+ case SND_CTL_ELEM_TYPE_BOOLEAN:
+ *val = snd_ctl_elem_value_get_boolean(control, i);
+ break;
+ case SND_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < count; i++)
+ *val = snd_ctl_elem_value_get_integer(control, i);
+ break;
+ case SND_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < count; i++)
+ *val = snd_ctl_elem_value_get_enumerated(control, i);
+ break;
+ default:
+ AUDIO_LOG_WARN("unsupported control element type\n");
+ goto close;
+ }
+
+ snd_ctl_close(handle);
+
+#ifdef AUDIO_DEBUG
+ AUDIO_LOG_INFO("get mixer(%s) = %d success", ctl_name, *val);
+#endif
+
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR("Error\n");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_t _mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val)
+{
+ snd_ctl_t *handle;
+ snd_ctl_elem_value_t *control;
+ snd_ctl_elem_id_t *id;
+ snd_ctl_elem_info_t *info;
+ snd_ctl_elem_type_t type;
+ int ret = 0, count = 0, i = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_lock(&(ah->mixer.mutex));
+
+ ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
+ if (ret < 0) {
+ AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", ALSA_DEFAULT_CARD, snd_strerror(ret));
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_IOCTL;
+ }
+
+ // Get Element Info
+
+ snd_ctl_elem_id_alloca(&id);
+ snd_ctl_elem_info_alloca(&info);
+ snd_ctl_elem_value_alloca(&control);
+
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl_name);
+
+ snd_ctl_elem_info_set_id(info, id);
+ if (snd_ctl_elem_info(handle, info) < 0) {
+ AUDIO_LOG_ERROR("Cannot find control element: %s", ctl_name);
+ goto close;
+ }
+ snd_ctl_elem_info_get_id(info, id);
+
+ type = snd_ctl_elem_info_get_type(info);
+ count = snd_ctl_elem_info_get_count(info);
+
+ snd_ctl_elem_value_set_id(control, id);
+
+ snd_ctl_elem_read(handle, control);
+
+ switch (type) {
+ case SND_CTL_ELEM_TYPE_BOOLEAN:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_boolean(control, i, val);
+ break;
+ case SND_CTL_ELEM_TYPE_INTEGER:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_integer(control, i, val);
+ break;
+ case SND_CTL_ELEM_TYPE_ENUMERATED:
+ for (i = 0; i < count; i++)
+ snd_ctl_elem_value_set_enumerated(control, i, val);
+ break;
+
+ default:
+ AUDIO_LOG_WARN("unsupported control element type");
+ goto close;
+ }
+
+ snd_ctl_elem_write(handle, control);
+
+ snd_ctl_close(handle);
+
+ AUDIO_LOG_INFO("set mixer(%s) = %d success", ctl_name, val);
+
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_RET_OK;
+
+close:
+ AUDIO_LOG_ERROR("Error");
+ snd_ctl_close(handle);
+ pthread_mutex_unlock(&(ah->mixer.mutex));
+ return AUDIO_ERR_UNDEFINED;
+}
+
+audio_return_t _mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
+
+
+audio_return_t _mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(elem, AUDIO_ERR_PARAMETER);
+
+ /* TODO. */
+ return AUDIO_RET_OK;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+#ifdef __USE_TINYALSA__
+/* Convert pcm format from pulse to alsa */
+static const uint32_t g_format_convert_table[] = {
+ [AUDIO_SAMPLE_U8] = PCM_FORMAT_S8,
+ [AUDIO_SAMPLE_S16LE] = PCM_FORMAT_S16_LE,
+ [AUDIO_SAMPLE_S32LE] = PCM_FORMAT_S32_LE,
+ [AUDIO_SAMPLE_S24_32LE] = PCM_FORMAT_S24_LE
+};
+#else /* alsa-lib */
+/* FIXME : To avoid build warning... */
+int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
+/* Convert pcm format from pulse to alsa */
+static const uint32_t g_format_convert_table[] = {
+ [AUDIO_SAMPLE_U8] = SND_PCM_FORMAT_U8,
+ [AUDIO_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
+ [AUDIO_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
+ [AUDIO_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
+ [AUDIO_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
+ [AUDIO_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
+ [AUDIO_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
+ [AUDIO_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
+ [AUDIO_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
+ [AUDIO_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
+ [AUDIO_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
+ [AUDIO_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
+ [AUDIO_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE
+};
+#endif
+
+static uint32_t __convert_format(audio_sample_format_t format)
+{
+ return g_format_convert_table[format];
+}
+
+/* #define DEBUG_TIMING */
+
+static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
+{
+ snd_pcm_hw_params_t *params = NULL;
+ int err = 0;
+ unsigned int val = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ /* Skip parameter setting to null device. */
+ if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
+ return AUDIO_ERR_IOCTL;
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(¶ms);
+
+ /* 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, 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;
+}
+
+#ifdef __USE_TINYALSA__
+static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t period_size, size_t period_count, uint32_t direction)
+{
+ struct pcm *pcm = NULL;
+ struct pcm_config config;
+
+ AUDIO_RETURN_NULL_IF_FAIL(ss);
+
+ config.channels = ss->channels;
+ config.rate = ss->rate;
+ config.period_size = period_size;
+ config.period_count = period_count;
+ config.format = ss->format;
+ config.start_threshold = period_size;
+ config.stop_threshold = 0xFFFFFFFF;
+ config.silence_threshold = 0;
+
+ AUDIO_LOG_INFO("direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d", direction, ss->channels, ss->rate, ss->format, period_size, period_count);
+
+ pcm = pcm_open((direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_CARD_ID : CAPTURE_CARD_ID,
+ (direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_PCM_DEVICE_ID : CAPTURE_PCM_DEVICE_ID,
+ (direction == AUDIO_DIRECTION_OUT) ? PCM_OUT : PCM_IN,
+ &config);
+ if (!pcm || !pcm_is_ready(pcm)) {
+ AUDIO_LOG_ERROR("Unable to open device (%s)", pcm_get_error(pcm));
+ pcm_close(pcm);
+ return NULL;
+ }
+
+ return pcm;
+}
+
+static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
+{
+ if (err > 0)
+ err = -err;
+ if (err == -EINTR) /* nothing to do, continue */
+ return 0;
+ if (err == -EPIPE) {
+ AUDIO_LOG_INFO("XRUN occurred");
+ err = pcm_prepare(pcm);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Could not recover from XRUN occurred, prepare failed : %d", err);
+ return err;
+ }
+ return 0;
+ }
+ if (err == -ESTRPIPE) {
+ /* tinyalsa does not support pcm resume, dont't care suspend case */
+ AUDIO_LOG_ERROR("Could not recover from suspend : %d", err);
+ return err;
+ }
+ return err;
+}
+#endif
+
+int _voice_pcm_open(audio_hal_t *ah)
+{
+ int err, ret = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("open voice pcm handles");
+
+ /* Get playback voice-pcm from ucm conf. Open and set-params */
+ if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(ah, ah->device.pcm_out);
+
+ AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
+
+ /* Get capture voice-pcm from ucm conf. Open and set-params */
+ if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
+ return AUDIO_ERR_IOCTL;
+ }
+ ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
+ AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
+
+ return ret;
+}
+
+int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("close voice pcm handles");
+
+ if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
+ _pcm_close(ah->device.pcm_out);
+ ah->device.pcm_out = NULL;
+ AUDIO_LOG_INFO("voice pcm_out handle close success");
+ } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
+ _pcm_close(ah->device.pcm_in);
+ ah->device.pcm_in = NULL;
+ AUDIO_LOG_INFO("voice pcm_in handle close success");
+ }
+
+ return AUDIO_RET_OK;
+}
+
+void _reset_pcm_devices(audio_hal_t *ah)
+{
+ AUDIO_RETURN_IF_FAIL(ah);
+
+ if (ah->device.pcm_out) {
+ _pcm_close(ah->device.pcm_out);
+ ah->device.pcm_out = NULL;
+ AUDIO_LOG_INFO("pcm_out handle close success");
+ }
+ if (ah->device.pcm_in) {
+ _pcm_close(ah->device.pcm_in);
+ ah->device.pcm_in = NULL;
+ AUDIO_LOG_INFO("pcm_in handle close success");
+ }
+
+ return;
+}
+
+audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+#ifdef __USE_TINYALSA__
+ audio_pcm_sample_spec_t *ss;
+ int err;
+
+ ss = (audio_pcm_sample_spec_t *)sample_spec;
+ ss->format = __convert_format((audio_sample_format_t)ss->format);
+
+ *pcm_handle = __tinyalsa_open_device(ss, (size_t)period_size, (size_t)periods, direction);
+ if (*pcm_handle == NULL) {
+ AUDIO_LOG_ERROR("Error opening PCM device");
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((err = pcm_prepare((struct pcm *)*pcm_handle)) != 0) {
+ AUDIO_LOG_ERROR("Error prepare PCM device : %d", err);
+ }
+
+#else /* alsa-lib */
+ int err, mode;
+ char *device_name = NULL;
+
+ mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
+
+ if (direction == AUDIO_DIRECTION_OUT)
+ device_name = PLAYBACK_PCM_DEVICE;
+ else if (direction == AUDIO_DIRECTION_IN)
+ device_name = CAPTURE_PCM_DEVICE;
+ else {
+ AUDIO_LOG_ERROR("Error get device_name, direction : %d", direction);
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((err = snd_pcm_open((snd_pcm_t **)pcm_handle, device_name, (direction == AUDIO_DIRECTION_OUT) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, mode)) < 0) {
+ AUDIO_LOG_ERROR("Error opening PCM device %s : %s", device_name, snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+
+ if ((err = _pcm_set_params(*pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
+ AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", err);
+ return err;
+ }
+
+ AUDIO_LOG_INFO("PCM device %s", device_name);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_start(void *pcm_handle)
+{
+ int err;
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_start(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error starting PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_start(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error starting PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ AUDIO_LOG_INFO("PCM handle 0x%x start", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_stop(void *pcm_handle)
+{
+ int err;
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_stop(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error stopping PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_drop(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error stopping PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ AUDIO_LOG_INFO("PCM handle 0x%x stop", pcm_handle);
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_close(void *pcm_handle)
+{
+ int err;
+
+ AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
+
+#ifdef __USE_TINYALSA__
+ if ((err = pcm_close(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error closing PCM handle : %d", err);
+ return AUDIO_ERR_RESOURCE;
+ }
+#else /* alsa-lib */
+ if ((err = snd_pcm_close(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
+ return AUDIO_ERR_RESOURCE;
+ }
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail)
+{
+#ifdef __USE_TINYALSA__
+ struct timespec tspec;
+ unsigned int frames_avail = 0;
+ int err;
+
+ err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle 0x%x : %d", pcm_handle, err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("avail = %d", frames_avail);
+#endif
+
+ *avail = (uint32_t)frames_avail;
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_avail;
+
+ if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not get avail at PCM handle 0x%x : %d", pcm_handle, frames_avail);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("avail = %d", frames_avail);
+#endif
+
+ *avail = (uint32_t)frames_avail;
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ err = pcm_write(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Failed to write pcm : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_write = %d", frames);
+#endif
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_written;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ frames_written = snd_pcm_writei(pcm_handle, buffer, (snd_pcm_uframes_t) frames);
+ if (frames_written < 0) {
+ AUDIO_LOG_ERROR("Failed to write pcm : %d", frames_written);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_write = (%d / %d)", frames_written, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
+{
+#ifdef __USE_TINYALSA__
+ int err;
+
+ err = pcm_read(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
+ if (err < 0) {
+ AUDIO_LOG_ERROR("Failed to read pcm : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("audio_pcm_read = %d", frames);
+#endif
+#else /* alsa-lib */
+ snd_pcm_sframes_t frames_read;
+
+ frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
+ if (frames_read < 0) {
+ AUDIO_LOG_ERROR("Failed to read pcm : %d", frames_read);
+ return AUDIO_ERR_IOCTL;
+ }
+
+#ifdef DEBUG_TIMING
+ AUDIO_LOG_DEBUG("_pcm_read = (%d / %d)", frames_read, frames);
+#endif
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_get_fd(void *pcm_handle, int *fd)
+{
+ /* we use an internal API of the (tiny)alsa library, so it causes warning message during compile */
+#ifdef __USE_TINYALSA__
+ *fd = _pcm_poll_descriptor((struct pcm *)pcm_handle);
+#else /* alsa-lib */
+ *fd = _snd_pcm_poll_descriptor((snd_pcm_t *)pcm_handle);
+#endif
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_recover(void *pcm_handle, int revents)
+{
+ int state, err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ if (revents & POLLERR)
+ AUDIO_LOG_DEBUG("Got POLLERR from ALSA");
+ if (revents & POLLNVAL)
+ AUDIO_LOG_DEBUG("Got POLLNVAL from ALSA");
+ if (revents & POLLHUP)
+ AUDIO_LOG_DEBUG("Got POLLHUP from ALSA");
+ if (revents & POLLPRI)
+ AUDIO_LOG_DEBUG("Got POLLPRI from ALSA");
+ if (revents & POLLIN)
+ AUDIO_LOG_DEBUG("Got POLLIN from ALSA");
+ if (revents & POLLOUT)
+ AUDIO_LOG_DEBUG("Got POLLOUT from ALSA");
+
+#ifdef __USE_TINYALSA__
+ state = pcm_state(pcm_handle);
+ AUDIO_LOG_DEBUG("PCM state is %d", state);
+
+ switch (state) {
+ case PCM_STATE_XRUN:
+ if ((err = __tinyalsa_pcm_recover(pcm_handle, -EPIPE)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ case PCM_STATE_SUSPENDED:
+ if ((err = __tinyalsa_pcm_recover(pcm_handle, -ESTRPIPE)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ default:
+ pcm_stop(pcm_handle);
+ if ((err = pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with pcm_prepare() : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ }
+#else /* alsa-lib */
+ state = snd_pcm_state(pcm_handle);
+ AUDIO_LOG_DEBUG("PCM state is %s", snd_pcm_state_name(state));
+
+ /* Try to recover from this error */
+
+ switch (state) {
+ case SND_PCM_STATE_XRUN:
+ if ((err = snd_pcm_recover(pcm_handle, -EPIPE, 1)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ case SND_PCM_STATE_SUSPENDED:
+ if ((err = snd_pcm_recover(pcm_handle, -ESTRPIPE, 1)) != 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+
+ default:
+ snd_pcm_drop(pcm_handle);
+ if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare() : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+ break;
+ }
+#endif
+
+ AUDIO_LOG_DEBUG("_pcm_recover");
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
+{
+#ifdef __USE_TINYALSA__
+ audio_pcm_sample_spec_t *ss;
+ unsigned int _period_size, _buffer_size, _periods, _format, _rate, _channels;
+ unsigned int _start_threshold, _stop_threshold, _silence_threshold;
+ struct pcm_config *config;
+
+ ss = (audio_pcm_sample_spec_t *)*sample_spec;
+
+ /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
+ _pcm_config(pcm_handle, &config);
+
+ *period_size = config->period_size;
+ *periods = config->period_count;
+ _buffer_size = config->period_size * config->period_count;
+ ss->format = config->format;
+ ss->rate = config->rate;
+ ss->channels = config->channels;
+ _start_threshold = config->start_threshold;
+ _stop_threshold = config->stop_threshold;
+ _silence_threshold = config->silence_threshold;
+
+ AUDIO_LOG_DEBUG("_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, config->format, config->rate, config->channels, config->period_size, config->period_count, _buffer_size);
+#else /* alsa-lib */
+ int err;
+ audio_pcm_sample_spec_t *ss;
+ int dir;
+ snd_pcm_uframes_t _period_size, _buffer_size;
+ snd_pcm_format_t _format;
+ unsigned int _rate, _channels;
+ snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
+ unsigned int _periods;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = (audio_pcm_sample_spec_t *)*sample_spec;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_sw_params_alloca(&swparams);
+
+ if ((err = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_current() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0 ||
+ (err = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_format(hwparams, &_format)) < 0 ||
+ (err = snd_pcm_hw_params_get_rate(hwparams, &_rate, &dir)) < 0 ||
+ (err = snd_pcm_hw_params_get_channels(hwparams, &_channels)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %s", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ *period_size = _period_size;
+ *periods = _periods;
+ ss->format = _format;
+ ss->rate = _rate;
+ ss->channels = _channels;
+
+ if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_get_start_threshold(swparams, &_start_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_stop_threshold(swparams, &_stop_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_silence_threshold(swparams, &_silence_threshold)) < 0 ||
+ (err = snd_pcm_sw_params_get_avail_min(swparams, &_avail_min)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %s", err);
+ }
+
+ AUDIO_LOG_DEBUG("_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+#ifdef __USE_TINYALSA__
+ /* Parameters are only acceptable in pcm_open() function */
+ AUDIO_LOG_DEBUG("_pcm_set_params");
+#else /* alsa-lib */
+ int err;
+ audio_pcm_sample_spec_t ss;
+ snd_pcm_uframes_t _buffer_size;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ ss = *(audio_pcm_sample_spec_t *)sample_spec;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+ snd_pcm_sw_params_alloca(&swparams);
+
+ /* Set hw params */
+ if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate_resample() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ ss.format = __convert_format((audio_sample_format_t)ss.format);
+ if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, ss.format)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_format() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_period_size(pcm_handle, hwparams, period_size, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size(%u) failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods(%u) failed : %d", periods, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ _buffer_size = period_size * periods;
+ if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, _buffer_size)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size(%u) failed : %d", periods * periods, err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ /* Set sw params */
+ if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("Unable to determine current swparams : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm_handle, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
+ AUDIO_LOG_ERROR("Unable to enable time stamping : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xFFFFFFFF)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set stop threshold : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, period_size / 2)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set start threshold : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, 1024)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) {
+ AUDIO_LOG_ERROR("Unable to set sw params : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ /* Prepare device */
+ if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_prepare() failed : %d", err);
+ return AUDIO_ERR_IOCTL;
+ }
+
+ AUDIO_LOG_DEBUG("_pcm_set_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, ss.format, ss.rate, ss.channels, period_size, periods, _buffer_size);
+#endif
+
+ return AUDIO_RET_OK;
+}
+
+/* Generic snd pcm interface APIs */
+audio_return_t _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size)
+{
+ audio_return_t ret = AUDIO_RET_OK;
+ snd_pcm_hw_params_t *hwparams;
+ int err = 0;
+ int dir;
+ unsigned int val = 0;
+ snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
+ snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
+ uint8_t _use_mmap = use_mmap && *use_mmap;
+ uint32_t channels = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ /* Skip parameter setting to null device. */
+ if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
+ return AUDIO_ERR_IOCTL;
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ /* Fill it in with default values. */
+ if (snd_pcm_hw_params_any(pcm, hwparams) < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Set the desired hardware parameters. */
+
+ if (_use_mmap) {
+
+ if (snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
+
+ /* mmap() didn't work, fall back to interleaved */
+
+ if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ _use_mmap = 0;
+ }
+
+ } else if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+ AUDIO_LOG_DEBUG("setting rate - %d", sample_spec->rate);
+ err = snd_pcm_hw_params_set_rate(pcm, hwparams, sample_spec->rate, 0);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
+ }
+
+ err = snd_pcm_hw_params(pcm, hwparams);
+ if (err < 0) {
+ AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
+ goto error;
+ }
+
+ /* Dump current param */
+
+ if ((ret = snd_pcm_hw_params_current(pcm, hwparams)) < 0) {
+ AUDIO_LOG_INFO("snd_pcm_hw_params_current() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
+ (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
+ AUDIO_LOG_INFO("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", snd_strerror(ret));
+ goto error;
+ }
+
+ snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
+ AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
+
+ snd_pcm_hw_params_get_format(hwparams, &sample_spec->format);
+ AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
+ snd_pcm_format_name((snd_pcm_format_t)sample_spec->format),
+ snd_pcm_format_description((snd_pcm_format_t)sample_spec->format));
+
+ snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
+ AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
+ snd_pcm_subformat_name((snd_pcm_subformat_t)val),
+ snd_pcm_subformat_description((snd_pcm_subformat_t)val));
+
+ snd_pcm_hw_params_get_channels(hwparams, &channels);
+ sample_spec->channels = (uint8_t)channels;
+ AUDIO_LOG_DEBUG("channels = %d\n", sample_spec->channels);
+
+ if (buffer_size)
+ *buffer_size = _buffer_size;
+
+ if (period_size)
+ *period_size = _period_size;
+
+ if (use_mmap)
+ *use_mmap = _use_mmap;
+
+ return AUDIO_RET_OK;
+
+error:
+ return AUDIO_ERR_RESOURCE;
+}
+
+audio_return_t _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event)
+{
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_uframes_t boundary;
+ int err;
+
+ AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
+
+ snd_pcm_sw_params_alloca(&swparams);
+
+ if ((err = snd_pcm_sw_params_current(pcm, swparams)) < 0) {
+ AUDIO_LOG_WARN("Unable to determine current swparams: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
+ AUDIO_LOG_WARN("Unable to disable period event: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
+ AUDIO_LOG_WARN("Unable to enable time stamping: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
+ AUDIO_LOG_WARN("Unable to get boundary: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
+ AUDIO_LOG_WARN("Unable to set stop threshold: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) avail_min)) < 0) {
+ AUDIO_LOG_WARN("Unable to set start threshold: %s\n", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
+ AUDIO_LOG_WARN("snd_pcm_sw_params_set_avail_min() failed: %s", snd_strerror(err));
+ goto error;
+ }
+ if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
+ AUDIO_LOG_WARN("Unable to set sw params: %s\n", snd_strerror(err));
+ goto error;
+ }
+ return AUDIO_RET_OK;
+error:
+ return err;
+}
\ No newline at end of file
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#define UCM_PREFIX_REQUESTED "> UCM requested"
#define UCM_PREFIX_CHANGED "<<< UCM changed"
-audio_return_t _audio_ucm_init(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
-
- if (!ah->ucm.uc_mgr) {
- AUDIO_LOG_ERROR("uc_mgr open failed");
- return AUDIO_ERR_RESOURCE;
- }
- return AUDIO_RET_OK;
-}
-
-audio_return_t _audio_ucm_deinit(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
-
- snd_use_case_mgr_close(ah->ucm.uc_mgr);
- ah->ucm.uc_mgr = NULL;
-
- return AUDIO_RET_OK;
-}
-
-void _audio_ucm_get_device_name(audio_hal_t *ah, const char *use_case, audio_direction_t direction, const char **value)
-{
- char identifier[70] = { 0, };
-
- AUDIO_RETURN_IF_FAIL(ah);
- AUDIO_RETURN_IF_FAIL(ah->ucm.uc_mgr);
-
- snprintf(identifier, sizeof(identifier), "%sPCM//%s",
- (direction == AUDIO_DIRECTION_IN) ? "Capture" : "Playback", use_case);
-
- snd_use_case_get(ah->ucm.uc_mgr, identifier, value);
-}
-
-static inline void __add_ucm_device_info(audio_hal_t *ah, 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_RETURN_IF_FAIL(ah);
- AUDIO_RETURN_IF_FAIL(ah->ucm.uc_mgr);
- AUDIO_RETURN_IF_FAIL(device_info_list);
- AUDIO_RETURN_IF_FAIL(device_info_count);
-
- _audio_ucm_get_device_name(ah, 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_hal_t *ah, audio_device_info_t *device_info_list, const char *verb)
-{
- int device_info_count = 0;
- const char *curr_verb = NULL;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, device_info_count);
- AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, device_info_count);
- AUDIO_RETURN_VAL_IF_FAIL(device_info_list, device_info_count);
-
- if (!verb) {
- snd_use_case_get(ah->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(ah, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
-#if 0 /* disable temporarily */
- if (strncmp(verb, AUDIO_USE_CASE_VERB_FMRADIO, strlen(AUDIO_USE_CASE_VERB_FMRADIO))) {
- __add_ucm_device_info(ah, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
- }
-#endif
- }
-
- if (curr_verb)
- free((void *)curr_verb);
-
- }
-
- return device_info_count;
-}
-
#define DUMP_LEN 512
static void __dump_use_case(const char* prefix, const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count)
int i;
dump_data_t* dump = NULL;
- if (!(dump = dump_new(DUMP_LEN))) {
+ if (!(dump = _audio_dump_new(DUMP_LEN))) {
AUDIO_LOG_ERROR("Failed to create dump string...");
return;
}
/* Verb */
- dump_add_str(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
+ _audio_dump_add_str(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
/* Devices */
if (devices) {
for (i = 0; i < dev_count; i++) {
- dump_add_str(dump, (i != dev_count - 1) ? "%s, " : "%s", devices[i]);
+ _audio_dump_add_str(dump, (i != dev_count - 1) ? "%s, " : "%s", devices[i]);
}
}
- dump_add_str(dump, " ] Modifier [ ");
+ _audio_dump_add_str(dump, " ] Modifier [ ");
/* Modifiers */
if (modifiers) {
for (i = 0; i < mod_count; i++) {
- dump_add_str(dump, (i != mod_count - 1) ? "%s, " : "%s", modifiers[i]);
+ _audio_dump_add_str(dump, (i != mod_count - 1) ? "%s, " : "%s", modifiers[i]);
}
}
- dump_add_str(dump, " ]");
+ _audio_dump_add_str(dump, " ]");
- AUDIO_LOG_INFO("TEST %s : %s", prefix, dump_get_str(dump));
+ AUDIO_LOG_INFO("TEST %s : %s", prefix, _audio_dump_get_str(dump));
- dump_free(dump);
+ _audio_dump_free(dump);
}
#ifdef ALSA_UCM_DEBUG_TIME
}
#endif
+audio_return_t _ucm_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
+
+ if (!ah->ucm.uc_mgr) {
+ AUDIO_LOG_ERROR("uc_mgr open failed");
+ return AUDIO_ERR_RESOURCE;
+ }
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _ucm_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
+
+ if (ah->ucm.uc_mgr) {
+ snd_use_case_mgr_close(ah->ucm.uc_mgr);
+ ah->ucm.uc_mgr = NULL;
+ }
+
+ return AUDIO_RET_OK;
+}
+
/* UCM sequence
1) If verb is null or verb is not changed
1-1) If device is changed
2) If verb is changed
-> Reset, set new verb, enable devices & modifiers
*/
-audio_return_t _audio_ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[])
+audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[])
{
audio_return_t audio_ret = AUDIO_RET_OK;
int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
return audio_ret;
}
-audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[])
+audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[])
{
audio_return_t audio_ret = AUDIO_RET_OK;
int is_verb_changed = 0, is_dev_changed = 0;
}
-audio_return_t _audio_ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[])
+audio_return_t _ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[])
{
audio_return_t audio_ret = AUDIO_RET_OK;
int is_verb_changed = 0, is_mod_changed = 0;
return audio_ret;
}
-audio_return_t _audio_ucm_get_verb(audio_hal_t *ah, const char **value)
+audio_return_t _ucm_get_verb(audio_hal_t *ah, const char **value)
{
audio_return_t ret = AUDIO_RET_OK;
return ret;
}
-
-audio_return_t _audio_ucm_reset_use_case(audio_hal_t *ah)
+audio_return_t _ucm_reset_use_case(audio_hal_t *ah)
{
audio_return_t ret = AUDIO_RET_OK;
}
return ret;
-}
-
+}
\ No newline at end of file
--- /dev/null
+#ifndef footizenaudioimplfoo
+#define footizenaudioimplfoo
+
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* PCM */
+int _voice_pcm_open(audio_hal_t *ah);
+int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
+void _reset_pcm_devices(audio_hal_t *ah);
+audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_t _pcm_start(void *pcm_handle);
+audio_return_t _pcm_stop(void *pcm_handle);
+audio_return_t _pcm_close(void *pcm_handle);
+audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail);
+audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames);
+audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames);
+audio_return_t _pcm_get_fd(void *pcm_handle, int *fd);
+audio_return_t _pcm_recover(void *pcm_handle, int revents);
+audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods);
+audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
+audio_return_t _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event);
+audio_return_t _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size);
+
+/* Control */
+audio_return_t _control_init(audio_hal_t *ah);
+audio_return_t _control_deinit(audio_hal_t *ah);
+audio_return_t _mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
+audio_return_t _mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val);
+audio_return_t _mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value);
+audio_return_t _mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val);
+audio_return_t _mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem);
+
+/* UCM */
+audio_return_t _ucm_init(audio_hal_t *ah);
+audio_return_t _ucm_deinit(audio_hal_t *ah);
+#define _ucm_update_use_case _ucm_set_use_case
+audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[]);
+audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[]);
+audio_return_t _ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[]);
+audio_return_t _ucm_get_verb(audio_hal_t *ah, const char **value);
+audio_return_t _ucm_reset_use_case(audio_hal_t *ah);
+
+#endif
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* type definitions */
typedef signed char int8_t;
-/* pcm */
+/* PCM */
typedef struct {
snd_pcm_format_t format;
uint32_t rate;
uint8_t channels;
} audio_pcm_sample_spec_t;
-/* Device */
-typedef enum audio_device_api {
- AUDIO_DEVICE_API_UNKNOWN,
- AUDIO_DEVICE_API_ALSA,
- AUDIO_DEVICE_API_BLUEZ,
-} audio_device_api_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;
-
+/* Routing */
typedef enum audio_route_mode {
VERB_NORMAL,
VERB_VOICECALL,
pthread_mutex_t device_lock;
} audio_hal_device_t;
-/* Stream */
+/* Volume */
#define AUDIO_VOLUME_LEVEL_MAX 16
typedef enum audio_volume {
audio_volume_value_table_t *volume_value_table;
} audio_hal_volume_t;
+/* UCM */
typedef struct audio_hal_ucm {
snd_use_case_mgr_t* uc_mgr;
} audio_hal_ucm_t;
+/* Mixer */
typedef struct audio_hal_mixer {
snd_mixer_t *mixer;
pthread_mutex_t mutex;
AUDIO_SAMPLE_INVALID = -1
} audio_sample_format_t;
+/* Modem */
typedef struct audio_hal_modem {
-
struct {
pthread_t voice_thread_handle;
pthread_t voip_thread_handle;
audio_return_t _audio_volume_init(audio_hal_t *ah);
audio_return_t _audio_volume_deinit(audio_hal_t *ah);
-audio_return_t _audio_device_init(audio_hal_t *ah);
-audio_return_t _audio_device_deinit(audio_hal_t *ah);
-audio_return_t _audio_ucm_init(audio_hal_t *ah);
-audio_return_t _audio_ucm_deinit(audio_hal_t *ah);
+audio_return_t _audio_routing_init(audio_hal_t *ah);
+audio_return_t _audio_routing_deinit(audio_hal_t *ah);
+audio_return_t _audio_stream_init(audio_hal_t *ah);
+audio_return_t _audio_stream_deinit(audio_hal_t *ah);
+audio_return_t _audio_pcm_init(audio_hal_t *ah);
+audio_return_t _audio_pcm_deinit(audio_hal_t *ah);
audio_return_t _audio_modem_init(audio_hal_t *ah);
audio_return_t _audio_modem_deinit(audio_hal_t *ah);
audio_return_t _audio_comm_init(audio_hal_t *ah);
audio_return_t _audio_comm_deinit(audio_hal_t *ah);
-audio_return_t _audio_util_init(audio_hal_t *ah);
-audio_return_t _audio_util_deinit(audio_hal_t *ah);
audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices);
-void _audio_ucm_get_device_name(audio_hal_t *ah, 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_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[]);
-audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[]);
-audio_return_t _audio_ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[]);
-int _audio_ucm_fill_device_info_list(audio_hal_t *ah, audio_device_info_t *device_info_list, const char *verb);
-audio_return_t _audio_ucm_get_verb(audio_hal_t *ah, const char **value);
-audio_return_t _audio_ucm_reset_use_case(audio_hal_t *ah);
int _audio_modem_is_call_connected(audio_hal_t *ah);
audio_return_t _audio_comm_send_message(audio_hal_t *ah, const char *name, int value);
-audio_return_t _audio_comm_set_message_callback(audio_hal_t *ah, message_cb callback, void *user_data);
-audio_return_t _audio_comm_unset_message_callback(audio_hal_t *ah);
-audio_return_t _audio_mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* value, int size);
-audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val);
-audio_return_t _audio_mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value);
-audio_return_t _audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val);
-audio_return_t _audio_mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem);
-audio_return_t _audio_pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event);
-audio_return_t _audio_pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size);
-uint32_t _convert_format(audio_sample_format_t format);
typedef struct _dump_data {
char *strbuf;
char *p;
} dump_data_t;
-dump_data_t* dump_new(int length);
-void dump_add_str(dump_data_t *dump, const char *fmt, ...);
-char* dump_get_str(dump_data_t *dump);
-void dump_free(dump_data_t *dump);
+dump_data_t* _audio_dump_new(int length);
+void _audio_dump_add_str(dump_data_t *dump, const char *fmt, ...);
+char* _audio_dump_get_str(dump_data_t *dump);
+void _audio_dump_free(dump_data_t *dump);
#endif
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Contact:
*
#include <vconf.h>
#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
#define vbc_thread_new pthread_create
#define MIXER_VBC_SWITCH "VBC Switch"
{
int val = -1; /* Mixer values 0 - cp [3g] ,1 - cp [2g] ,2 - ap */
- _audio_mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
+ _mixer_control_get_value(ah, MIXER_VBC_SWITCH, &val);
AUDIO_LOG_INFO("modem is connected for call = %d", (val == VBC_TD_CHANNELID));
return (val == VBC_TD_CHANNELID) ? 1 : 0;
}
#define FM_IIS 0x10
-static void i2s_pin_mux_sel(audio_hal_t *ah, int type)
+static void __i2s_pin_mux_sel(audio_hal_t *ah, int type)
{
audio_return_t ret = AUDIO_RET_OK;
audio_modem_t *modem;
modem = ah->modem.cp;
if (type == FM_IIS) {
- _audio_mixer_control_set_value(ah,
+ _mixer_control_set_value(ah,
PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_VBC_ID);
return;
}
if(ah->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(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP0_ID);
}
} else {
if(modem->i2s_bt.is_switch) {
int value = 0;
- _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
+ _mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
if(value == PIN_SWITCH_IIS0_CP0_ID) {
- ret = _audio_mixer_control_set_value(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_AP_ID);
}
}
if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
if(modem->i2s_bt.is_switch) {
- ret = _audio_mixer_control_set_value(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP0_IIS0_ID);
}
}
if(ah->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(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP1_ID);
}
} else {
if(modem->i2s_bt.is_switch) {
int value = 0;
- _audio_mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
+ _mixer_control_get_value (ah, PIN_SWITCH_IIS0_SYS_SEL, &value);
if(value == PIN_SWITCH_IIS0_CP1_ID) {
- ret = _audio_mixer_control_set_value(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_IIS0_SYS_SEL, PIN_SWITCH_IIS0_CP2_ID);
}
}
if(ah->device.active_out & AUDIO_DEVICE_OUT_BT_SCO) {
if(modem->i2s_bt.is_switch) {
- ret = _audio_mixer_control_set_value(ah,
+ ret = _mixer_control_set_value(ah,
PIN_SWITCH_BT_IIS_SYS_SEL, PIN_SWITCH_BT_IIS_CP1_IIS0_ID);
}
}
AUDIO_LOG_INFO("[voice] Received VBC_CMD_PCM_OPEN");
ah->modem.is_connected = 1;
- audio_ret = _audio_update_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices);
- if (AUDIO_IS_ERROR(audio_ret)) {
+ if ((audio_ret = _audio_update_route_voicecall(ah, ah->device.init_call_devices, ah->device.num_of_call_devices))) {
AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
if (audio_ret == AUDIO_ERR_INVALID_STATE) {
/* send signal and wait for the ucm setting,
if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
if (ah->modem.cp_type == CP_TG)
- i2s_pin_mux_sel(ah, 1);
+ __i2s_pin_mux_sel(ah, 1);
else if(ah->modem.cp_type == CP_W)
- i2s_pin_mux_sel(ah, 0);
+ __i2s_pin_mux_sel(ah, 0);
}
AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_OPEN");
COND_TIMEDWAIT(ah->device.device_cond, ah->device.device_lock, "device_cond", TIMEOUT_SEC);
MUTEX_UNLOCK(ah->device.device_lock, "device_lock");
- _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
+ _mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_ARM_CHANNELID);
AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_PCM_CLOSE");
__vbc_write_response(vbpipe_fd, VBC_CMD_PCM_CLOSE, 0);
if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
if (ah->modem.cp_type == CP_TG)
- i2s_pin_mux_sel(ah, 1);
+ __i2s_pin_mux_sel(ah, 1);
else if(ah->modem.cp_type == CP_W)
- i2s_pin_mux_sel(ah, 0);
+ __i2s_pin_mux_sel(ah, 0);
}
/* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
else
AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
- _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+ _mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
AUDIO_LOG_DEBUG("[voice] Send response for VBC_CMD_SET_GAIN");
__vbc_write_response(vbpipe_fd, VBC_CMD_SWITCH_CTRL, 0);
if (ah->device.active_out & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_BT_SCO)) {
if (ah->modem.cp_type == CP_TG)
- i2s_pin_mux_sel(ah, 1);
+ __i2s_pin_mux_sel(ah, 1);
else if(ah->modem.cp_type == CP_W)
- i2s_pin_mux_sel(ah, 0);
+ __i2s_pin_mux_sel(ah, 0);
}
/* To do: set mode params : __vbc_set_mode_params(ah, vbpipe_fd); */
AUDIO_LOG_DEBUG("[voip] Send response for VBC_CMD_SET_MODE");
else
AUDIO_LOG_INFO("is_switch:%d", switch_ctrl_params.is_switch);
- _audio_mixer_control_set_value(ah, MIXER_VBC_SWITCH, VBC_TD_CHANNELID);
+ _mixer_control_set_value(ah, 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);
return AUDIO_RET_OK;
}
-static audio_return_t __vbc_control_close(audio_hal_t *ah)
+void __vbc_control_close(audio_hal_t *ah)
{
/* TODO. Make sure we always receive CLOSE command from modem and then close pcm device */
ah->modem.vbc.exit_vbc_thread = 1;
pthread_cancel(ah->modem.vbc.voice_thread_handle);
pthread_cancel(ah->modem.vbc.voip_thread_handle);
- return AUDIO_RET_OK;
+ return;
}
static void __audio_modem_create(audio_modem_t *modem, const char *num)
ah->modem.vbc.vbpipe_count = 0;
/* Initialize vbc interface */
- audio_ret = __vbc_control_open(ah);
- if (AUDIO_IS_ERROR(audio_ret)) {
+ if ((audio_ret = __vbc_control_open(ah))) {
AUDIO_LOG_ERROR("__vbc_control_open failed");
goto exit;
}
ah->modem.cp_type = ah->modem.cp->vbc_ctrl_pipe_info->cp_type;
/* This ctrl need to be set "0" always - SPRD */
- _audio_mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
+ _mixer_control_set_value(ah, PIN_SWITCH_BT_IIS_CON_SWITCH, 0);
exit:
return audio_ret;
--- /dev/null
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+audio_return_t _audio_pcm_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.pcm_in = NULL;
+ ah->device.pcm_out = NULL;
+ pthread_mutex_init(&ah->device.pcm_lock, NULL);
+ pthread_mutex_init(&ah->device.device_lock, NULL);
+ pthread_cond_init(&ah->device.device_cond, NULL);
+ ah->device.pcm_count = 0;
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_pcm_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ pthread_mutex_destroy(&ah->device.pcm_lock);
+ pthread_mutex_destroy(&ah->device.device_lock);
+ pthread_cond_destroy(&ah->device.device_cond);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _pcm_open(pcm_handle, direction, sample_spec, period_size, periods)))
+ return audio_ret;
+
+ ah = (audio_hal_t*)audio_handle;
+ ah->device.pcm_count++;
+ AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_pcm_start(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_start(pcm_handle);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_stop(pcm_handle);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = NULL;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _pcm_close(pcm_handle)))
+ return audio_ret;
+
+ pcm_handle = NULL;
+ ah = (audio_hal_t*)audio_handle;
+ ah->device.pcm_count--;
+
+ AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_avail(pcm_handle, avail);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_write(pcm_handle, buffer, frames);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_read(pcm_handle, buffer, frames);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_get_fd(pcm_handle, fd);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_recover(pcm_handle, revents);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_get_params(pcm_handle, direction, sample_spec, period_size, periods);
+
+ return audio_ret;
+}
+
+audio_return_t audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
+
+ audio_ret = _pcm_set_params(pcm_handle, direction, sample_spec, period_size, periods);
+
+ return audio_ret;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "tizen-audio-internal.h"
+#include "tizen-audio-impl.h"
+
+/* #define DEBUG_TIMING */
+
+static device_type_t outDeviceTypes[] = {
+ { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
+ { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
+ { AUDIO_DEVICE_OUT_JACK, "Headphones" },
+ { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
+ { 0, 0 },
+};
+
+static device_type_t inDeviceTypes[] = {
+ { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
+ { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
+ { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
+ { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
+ { 0, 0 },
+};
+
+static const char* mode_to_verb_str[] = {
+ AUDIO_USE_CASE_VERB_HIFI,
+ AUDIO_USE_CASE_VERB_VOICECALL,
+ AUDIO_USE_CASE_VERB_VIDEOCALL,
+ AUDIO_USE_CASE_VERB_VOIP,
+};
+
+static uint32_t __convert_device_string_to_enum(const char* device_str, uint32_t direction)
+{
+ uint32_t device = 0;
+
+ if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_SPEAKER;
+ } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
+ device = AUDIO_DEVICE_OUT_RECEIVER;
+ } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_JACK;
+ } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
+ device = AUDIO_DEVICE_OUT_BT_SCO;
+ } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
+ device = AUDIO_DEVICE_IN_MAIN_MIC;
+ /* To Do : SUB_MIC */
+ } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_JACK;
+ } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
+ device = AUDIO_DEVICE_IN_BT_SCO;
+ } else {
+ device = AUDIO_DEVICE_NONE;
+ }
+ AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
+ return device;
+}
+
+static void __reset_voice_devices_info(audio_hal_t *ah)
+{
+ AUDIO_RETURN_IF_FAIL(ah);
+
+ AUDIO_LOG_INFO("reset voice device info");
+ if (ah->device.init_call_devices) {
+ free(ah->device.init_call_devices);
+ ah->device.init_call_devices = NULL;
+ ah->device.num_of_call_devices = 0;
+ }
+
+ return;
+}
+
+static audio_return_t __set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ uint32_t new_device = 0;
+ const char *active_devices[MAX_DEVICES] = {NULL,};
+ int i = 0, j = 0, dev_idx = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
+
+ if (num_of_devices > MAX_DEVICES) {
+ num_of_devices = MAX_DEVICES;
+ AUDIO_LOG_ERROR("error: num_of_devices");
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if (devices[0].direction == AUDIO_DIRECTION_OUT) {
+ ah->device.active_out &= 0x0;
+ if (ah->device.active_in) {
+ /* check the active in devices */
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ }
+ }
+ } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
+ ah->device.active_in &= 0x0;
+ if (ah->device.active_out) {
+ /* check the active out devices */
+ for (j = 0; j < outDeviceTypes[j].type; j++) {
+ if (ah->device.active_out & outDeviceTypes[j].type)
+ active_devices[dev_idx++] = outDeviceTypes[j].name;
+ }
+ }
+ }
+
+ for (i = 0; i < num_of_devices; i++) {
+ new_device = __convert_device_string_to_enum(devices[i].type, devices[i].direction);
+ if (new_device & AUDIO_DEVICE_IN) {
+ for (j = 0; j < inDeviceTypes[j].type; j++) {
+ if (new_device == inDeviceTypes[j].type) {
+ active_devices[dev_idx++] = inDeviceTypes[j].name;
+ ah->device.active_in |= new_device;
+ }
+ }
+ } else {
+ for (j = 0; j < outDeviceTypes[j].type; j++) {
+ if (new_device == outDeviceTypes[j].type) {
+ active_devices[dev_idx++] = outDeviceTypes[j].name;
+ ah->device.active_out |= new_device;
+ }
+ }
+ }
+ }
+
+ if (active_devices[0] == NULL) {
+ AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ audio_ret = _ucm_set_devices(ah, verb, active_devices);
+ if (audio_ret)
+ AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
+
+ return audio_ret;
+}
+
+static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ device_info_t *devices = NULL;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+#if 0 /* Disable setting modifiers, because driver does not support it yet */
+ int mod_idx = 0;
+ const char *modifiers[MAX_MODIFIERS] = {NULL,};
+#endif
+
+ if (ah->modem.is_connected) {
+ AUDIO_LOG_INFO("modem is connected, skip verb[%s]", verb);
+ return audio_ret;
+ }
+
+ if (ah->device.mode != VERB_NORMAL) {
+ if (ah->device.mode == VERB_VOICECALL) {
+ __reset_voice_devices_info(ah);
+ COND_SIGNAL(ah->device.device_cond, "device_cond");
+ }
+ _reset_pcm_devices(ah);
+ ah->device.mode = VERB_NORMAL;
+ }
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
+
+ devices = route_info->device_infos;
+
+ AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
+
+ audio_ret = __set_devices(ah, verb, devices, route_info->num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ ah->device.mode = VERB_NORMAL;
+
+#if 0 /* Disable setting modifiers, because driver does not support it yet */
+ /* Set modifiers */
+ if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
+ } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
+ if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
+ else
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
+ } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
+ if (ah->device.active_out)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
+ } else {
+ if (ah->device.active_in)
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
+ else
+ modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
+ }
+ audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
+#endif
+ return audio_ret;
+}
+
+static audio_return_t __update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_VOICECALL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ /* if both params are 0, return error for invalid state,
+ * this error would be used to tizen-audio-modem.c */
+ AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voicecall++");
+
+ audio_ret = __set_devices(ah, verb, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+
+ if (ah->device.mode != VERB_VOICECALL) {
+ _voice_pcm_open(ah);
+ ah->device.mode = VERB_VOICECALL;
+ /* FIXME. Get network info and configure rate in pcm device */
+ }
+
+ return audio_ret;
+}
+
+static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_voip++");
+
+ audio_ret = __set_devices(ah, verb, devices, num_of_devices);
+ if (audio_ret) {
+ AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+ return audio_ret;
+ }
+ /* FIXME. If necessary, set VERB_VOIP */
+ ah->device.mode = VERB_NORMAL;
+
+ /* TO DO: Set modifiers */
+ return audio_ret;
+}
+
+static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ const char *active_devices[MAX_DEVICES] = {NULL,};
+ int i = 0, dev_idx = 0;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
+
+ if (direction == AUDIO_DIRECTION_OUT) {
+ ah->device.active_out &= 0x0;
+ if (ah->device.active_in) {
+ /* check the active in devices */
+ for (i = 0; i < inDeviceTypes[i].type; i++) {
+ if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
+ active_devices[dev_idx++] = inDeviceTypes[i].name;
+ AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
+ }
+ }
+ }
+ } else {
+ ah->device.active_in &= 0x0;
+ if (ah->device.active_out) {
+ /* check the active out devices */
+ for (i = 0; i < outDeviceTypes[i].type; i++) {
+ if (ah->device.active_out & outDeviceTypes[i].type) {
+ active_devices[dev_idx++] = outDeviceTypes[i].name;
+ AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
+ }
+ }
+ }
+ }
+ if (ah->device.mode == VERB_VOICECALL) {
+ _voice_pcm_close(ah, direction);
+ if (!ah->device.active_in && !ah->device.active_out)
+ ah->device.mode = VERB_NORMAL;
+ __reset_voice_devices_info(ah);
+ COND_SIGNAL(ah->device.device_cond, "device_cond");
+ }
+
+ if (active_devices[0] == NULL) {
+ AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
+ return AUDIO_RET_OK;
+ }
+
+ if ((audio_ret = _ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices)))
+ AUDIO_LOG_ERROR("failed to _ucm_set_devices(), ret(0x%x)", audio_ret);
+
+ return audio_ret;
+}
+
+audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+ return __update_route_voicecall(ah, devices, num_of_devices);
+}
+
+audio_return_t _audio_routing_init(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ ah->device.active_in = 0x0;
+ ah->device.active_out = 0x0;
+ ah->device.mode = VERB_NORMAL;
+
+ if ((audio_ret = _ucm_init(ah)))
+ AUDIO_LOG_ERROR("failed to _ucm_init(), ret(0x%x)", audio_ret);
+
+ return audio_ret;
+}
+
+audio_return_t _audio_routing_deinit(audio_hal_t *ah)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ if ((audio_ret = _ucm_deinit(ah)))
+ AUDIO_LOG_ERROR("failed to _ucm_deinit(), ret(0x%x)", audio_ret);
+
+ return audio_ret;
+}
+
+audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+ device_info_t *devices = NULL;
+ uint32_t prev_size;
+ int32_t i;
+ int32_t j;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s", info->role);
+
+ devices = info->device_infos;
+
+ if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
+ if (!ah->modem.is_connected) {
+ if (info->num_of_devices) {
+ if (!ah->device.num_of_call_devices) {
+ if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
+ memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
+ ah->device.num_of_call_devices = info->num_of_devices;
+ } else {
+ AUDIO_LOG_ERROR("failed to calloc");
+ audio_ret = AUDIO_ERR_RESOURCE;
+ goto ERROR;
+ }
+ } else if (ah->device.num_of_call_devices) {
+ prev_size = ah->device.num_of_call_devices;
+ if (prev_size == 2) {
+ /* There's a chance to be requested to change routing from user
+ * though two devices(for input/output) has already been set for call-voice routing.
+ * In this case, exchange an old device for a new device if it's direction is same as an old one's. */
+ for (i = 0; i < prev_size; i++) {
+ for (j = 0; j < info->num_of_devices; j++) {
+ if (devices[j].direction == ah->device.init_call_devices[i].direction &&
+ devices[j].id != ah->device.init_call_devices[i].id)
+ memcpy(&ah->device.init_call_devices[i], &devices[j], sizeof(device_info_t));
+ }
+ }
+ } else if (prev_size < 2) {
+ /* A device has already been added for call-voice routing,
+ * and now it is about to add a new device(input or output device). */
+ ah->device.num_of_call_devices += info->num_of_devices;
+ if ((ah->device.init_call_devices = (device_info_t*)realloc(ah->device.init_call_devices, sizeof(device_info_t)*ah->device.num_of_call_devices))) {
+ memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
+ } else {
+ AUDIO_LOG_ERROR("failed to realloc");
+ audio_ret = AUDIO_ERR_RESOURCE;
+ goto ERROR;
+ }
+ } else {
+ AUDIO_LOG_ERROR("invaild previous num. of call devices");
+ audio_ret = AUDIO_ERR_INTERNAL;
+ goto ERROR;
+ }
+ }
+ } else {
+ AUDIO_LOG_ERROR("failed to update route for call-voice, num_of_devices is 0");
+ audio_ret = AUDIO_ERR_PARAMETER;
+ goto ERROR;
+ }
+ AUDIO_LOG_INFO("modem is not ready, skip...");
+ } else {
+ if ((audio_ret = __update_route_voicecall(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voicecall route return 0x%x", audio_ret);
+
+ COND_SIGNAL(ah->device.device_cond, "device_cond");
+ }
+ } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
+ AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
+
+ } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
+ if ((audio_ret = __update_route_reset(ah, devices->direction)))
+ AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
+
+ } else {
+ /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
+ if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
+ AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
+ }
+
+ERROR:
+ return audio_ret;
+}
+
+audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
+
+ return audio_ret;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * audio-hal
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "tizen-audio-internal.h"
+
+/* Audio latency */
+static const char* AUDIO_LATENCY_LOW = "low";
+static const char* AUDIO_LATENCY_MID = "mid";
+static const char* AUDIO_LATENCY_HIGH = "high";
+static const char* AUDIO_LATENCY_VOIP = "voip";
+
+/* Latency msec */
+static const unsigned int PERIOD_TIME_FOR_ULOW_LATENCY_MSEC = 20;
+static const unsigned int PERIOD_TIME_FOR_LOW_LATENCY_MSEC = 25;
+static const unsigned int PERIOD_TIME_FOR_MID_LATENCY_MSEC = 50;
+static const unsigned int PERIOD_TIME_FOR_HIGH_LATENCY_MSEC = 75;
+static const unsigned int PERIOD_TIME_FOR_UHIGH_LATENCY_MSEC = 150;
+static const unsigned int PERIOD_TIME_FOR_VOIP_LATENCY_MSEC = 20;
+
+static const uint32_t g_size_table[] = {
+ [AUDIO_SAMPLE_U8] = 1,
+ [AUDIO_SAMPLE_ULAW] = 1,
+ [AUDIO_SAMPLE_ALAW] = 1,
+ [AUDIO_SAMPLE_S16LE] = 2,
+ [AUDIO_SAMPLE_S16BE] = 2,
+ [AUDIO_SAMPLE_FLOAT32LE] = 4,
+ [AUDIO_SAMPLE_FLOAT32BE] = 4,
+ [AUDIO_SAMPLE_S32LE] = 4,
+ [AUDIO_SAMPLE_S32BE] = 4,
+ [AUDIO_SAMPLE_S24LE] = 3,
+ [AUDIO_SAMPLE_S24BE] = 3,
+ [AUDIO_SAMPLE_S24_32LE] = 4,
+ [AUDIO_SAMPLE_S24_32BE] = 4
+};
+
+static int __sample_spec_valid(uint32_t rate, audio_sample_format_t format, uint32_t channels)
+{
+ if ((rate <= 0 ||
+ rate > (48000U*4U) ||
+ channels <= 0 ||
+ channels > 32U ||
+ format >= AUDIO_SAMPLE_MAX ||
+ format < AUDIO_SAMPLE_U8))
+ return 0;
+
+ AUDIO_LOG_ERROR("hal-latency - __sample_spec_valid() -> return true");
+
+ return 1;
+}
+
+static uint32_t __usec_to_bytes(uint64_t t, uint32_t rate, audio_sample_format_t format, uint32_t channels)
+{
+ uint32_t ret = (uint32_t) (((t * rate) / 1000000ULL)) * (g_size_table[format] * channels);
+ AUDIO_LOG_DEBUG("hal-latency - return %d", ret);
+ return ret;
+}
+
+static uint32_t __sample_size(audio_sample_format_t format)
+{
+ return g_size_table[format];
+}
+
+audio_return_t _audio_stream_init(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t _audio_stream_deinit(audio_hal_t *ah)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+ return AUDIO_RET_OK;
+}
+
+audio_return_t audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected)
+{
+ audio_return_t audio_ret = AUDIO_RET_OK;
+ audio_hal_t *ah = (audio_hal_t *)audio_handle;
+
+ AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
+
+ return audio_ret;
+}
+
+audio_return_t audio_get_buffer_attr(void *audio_handle,
+ uint32_t direction,
+ const char *latency,
+ uint32_t samplerate,
+ audio_sample_format_t format,
+ uint32_t channels,
+ uint32_t *maxlength,
+ uint32_t *tlength,
+ uint32_t *prebuf,
+ uint32_t *minreq,
+ uint32_t *fragsize)
+{
+ AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(latency, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(maxlength, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(tlength, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(prebuf, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(minreq, AUDIO_ERR_PARAMETER);
+ AUDIO_RETURN_VAL_IF_FAIL(fragsize, AUDIO_ERR_PARAMETER);
+
+ AUDIO_LOG_DEBUG("hal-latency - audio_get_buffer_attr(direction:%d, latency:%s, samplerate:%d, format:%d, channels:%d)", direction, latency, samplerate, format, channels);
+
+ uint32_t period_time = 0,
+ sample_per_period = 0;
+
+ if (__sample_spec_valid(samplerate, format, channels) == 0) {
+ return AUDIO_ERR_PARAMETER;
+ }
+
+ if (direction == AUDIO_DIRECTION_IN) {
+ if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_LOW");
+ period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * __sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_MID");
+ period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * __sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_HIGH");
+ period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * __sample_size(format);
+ } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_VOIP");
+ period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = -1;
+ *maxlength = -1;
+ *fragsize = sample_per_period * __sample_size(format);
+ } else {
+ AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ } else { /* AUDIO_DIRECTION_OUT */
+ if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_LOW");
+ period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (samplerate / 10) * __sample_size(format) * channels; /* 100ms */
+ *maxlength = -1;
+ *fragsize = 0;
+ } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_MID");
+ period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (uint32_t) __usec_to_bytes(200000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = -1;
+ } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_HIGH");
+ period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = -1;
+ *tlength = (uint32_t) __usec_to_bytes(400000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = -1;
+ } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
+ AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_VOIP");
+ period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
+ sample_per_period = (samplerate * period_time) / 1000;
+ *prebuf = 0;
+ *minreq = __usec_to_bytes(20000, samplerate, format, channels);
+ *tlength = __usec_to_bytes(100000, samplerate, format, channels);
+ *maxlength = -1;
+ *fragsize = 0;
+ } else {
+ AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
+ return AUDIO_ERR_UNDEFINED;
+ }
+ }
+
+ AUDIO_LOG_INFO("hal-latency - return attr --> prebuf:%d, minreq:%d, tlength:%d, maxlength:%d, fragsize:%d", *prebuf, *minreq, *tlength, *maxlength, *fragsize);
+ return AUDIO_RET_OK;
+}
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <pthread.h>
#include "tizen-audio-internal.h"
-audio_return_t _audio_util_init(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- pthread_mutex_init(&(ah->mixer.mutex), NULL);
- return AUDIO_RET_OK;
-}
-
-audio_return_t _audio_util_deinit(audio_hal_t *ah)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- pthread_mutex_destroy(&(ah->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_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* param, int size)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- /* TODO. */
- return AUDIO_RET_OK;
-}
-
-audio_return_t _audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
-{
- snd_ctl_t *handle;
- snd_ctl_elem_value_t *control;
- snd_ctl_elem_id_t *id;
- snd_ctl_elem_info_t *info;
- snd_ctl_elem_type_t type;
-
- int ret = 0, count = 0, i = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-
- pthread_mutex_lock(&(ah->mixer.mutex));
-
- ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
- if (ret < 0) {
- AUDIO_LOG_ERROR("snd_ctl_open error, %s\n", snd_strerror(ret));
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_ERR_IOCTL;
- }
-
- // Get Element Info
-
- snd_ctl_elem_id_alloca(&id);
- snd_ctl_elem_info_alloca(&info);
- snd_ctl_elem_value_alloca(&control);
-
- snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
- snd_ctl_elem_id_set_name(id, ctl_name);
-
- snd_ctl_elem_info_set_id(info, id);
- if (snd_ctl_elem_info(handle, info) < 0) {
- AUDIO_LOG_ERROR("Cannot find control element: %s\n", ctl_name);
- goto close;
- }
- snd_ctl_elem_info_get_id(info, id);
-
- type = snd_ctl_elem_info_get_type(info);
- count = snd_ctl_elem_info_get_count(info);
-
- snd_ctl_elem_value_set_id(control, id);
-
- if (snd_ctl_elem_read(handle, control) < 0) {
- AUDIO_LOG_ERROR("snd_ctl_elem_read failed \n");
- goto close;
-}
-
- switch (type) {
- case SND_CTL_ELEM_TYPE_BOOLEAN:
- *val = snd_ctl_elem_value_get_boolean(control, i);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER:
- for (i = 0; i < count; i++)
- *val = snd_ctl_elem_value_get_integer(control, i);
- break;
- case SND_CTL_ELEM_TYPE_ENUMERATED:
- for (i = 0; i < count; i++)
- *val = snd_ctl_elem_value_get_enumerated(control, i);
- break;
- default:
- AUDIO_LOG_WARN("unsupported control element type\n");
- goto close;
- }
-
- snd_ctl_close(handle);
-
-#ifdef AUDIO_DEBUG
- AUDIO_LOG_INFO("get mixer(%s) = %d success", ctl_name, *val);
-#endif
-
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_RET_OK;
-
-close:
- AUDIO_LOG_ERROR("Error\n");
- snd_ctl_close(handle);
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_ERR_UNDEFINED;
-}
-
-audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val)
-{
- snd_ctl_t *handle;
- snd_ctl_elem_value_t *control;
- snd_ctl_elem_id_t *id;
- snd_ctl_elem_info_t *info;
- snd_ctl_elem_type_t type;
- int ret = 0, count = 0, i = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
-
- pthread_mutex_lock(&(ah->mixer.mutex));
-
- ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
- if (ret < 0) {
- AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", ALSA_DEFAULT_CARD, snd_strerror(ret));
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_ERR_IOCTL;
- }
-
- // Get Element Info
-
- snd_ctl_elem_id_alloca(&id);
- snd_ctl_elem_info_alloca(&info);
- snd_ctl_elem_value_alloca(&control);
-
- snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
- snd_ctl_elem_id_set_name(id, ctl_name);
-
- snd_ctl_elem_info_set_id(info, id);
- if (snd_ctl_elem_info(handle, info) < 0) {
- AUDIO_LOG_ERROR("Cannot find control element: %s", ctl_name);
- goto close;
- }
- snd_ctl_elem_info_get_id(info, id);
-
- type = snd_ctl_elem_info_get_type(info);
- count = snd_ctl_elem_info_get_count(info);
-
- snd_ctl_elem_value_set_id(control, id);
-
- snd_ctl_elem_read(handle, control);
-
- switch (type) {
- case SND_CTL_ELEM_TYPE_BOOLEAN:
- for (i = 0; i < count; i++)
- snd_ctl_elem_value_set_boolean(control, i, val);
- break;
- case SND_CTL_ELEM_TYPE_INTEGER:
- for (i = 0; i < count; i++)
- snd_ctl_elem_value_set_integer(control, i, val);
- break;
- case SND_CTL_ELEM_TYPE_ENUMERATED:
- for (i = 0; i < count; i++)
- snd_ctl_elem_value_set_enumerated(control, i, val);
- break;
-
- default:
- AUDIO_LOG_WARN("unsupported control element type");
- goto close;
- }
-
- snd_ctl_elem_write(handle, control);
-
- snd_ctl_close(handle);
-
- AUDIO_LOG_INFO("set mixer(%s) = %d success", ctl_name, val);
-
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_RET_OK;
-
-close:
- AUDIO_LOG_ERROR("Error");
- snd_ctl_close(handle);
- pthread_mutex_unlock(&(ah->mixer.mutex));
- return AUDIO_ERR_UNDEFINED;
-}
-
-audio_return_t _audio_mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
-
- /* TODO. */
- return AUDIO_RET_OK;
-}
-
-
-audio_return_t _audio_mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem)
-{
- AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(elem, AUDIO_ERR_PARAMETER);
-
- /* TODO. */
- return AUDIO_RET_OK;
-}
-
-#ifdef __USE_TINYALSA__
-/* Convert pcm format from pulse to alsa */
-static const uint32_t g_format_convert_table[] = {
- [AUDIO_SAMPLE_U8] = PCM_FORMAT_S8,
- [AUDIO_SAMPLE_S16LE] = PCM_FORMAT_S16_LE,
- [AUDIO_SAMPLE_S32LE] = PCM_FORMAT_S32_LE,
- [AUDIO_SAMPLE_S24_32LE] = PCM_FORMAT_S24_LE
-};
-#else /* alsa-lib */
-/* Convert pcm format from pulse to alsa */
-static const uint32_t g_format_convert_table[] = {
- [AUDIO_SAMPLE_U8] = SND_PCM_FORMAT_U8,
- [AUDIO_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW,
- [AUDIO_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW,
- [AUDIO_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE,
- [AUDIO_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE,
- [AUDIO_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
- [AUDIO_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
- [AUDIO_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE,
- [AUDIO_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE,
- [AUDIO_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE,
- [AUDIO_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE,
- [AUDIO_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE,
- [AUDIO_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE
-};
-#endif
-
-uint32_t _convert_format(audio_sample_format_t format)
-{
- return g_format_convert_table[format];
-}
-
-/* Generic snd pcm interface APIs */
-audio_return_t _audio_pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size)
-{
- audio_return_t ret = AUDIO_RET_OK;
- snd_pcm_hw_params_t *hwparams;
- int err = 0;
- int dir;
- unsigned int val = 0;
- snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
- snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
- uint8_t _use_mmap = use_mmap && *use_mmap;
- uint32_t channels = 0;
-
- AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
-
- snd_pcm_hw_params_alloca(&hwparams);
-
- /* Skip parameter setting to null device. */
- if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
- return AUDIO_ERR_IOCTL;
-
- /* Allocate a hardware parameters object. */
- snd_pcm_hw_params_alloca(&hwparams);
-
- /* Fill it in with default values. */
- if (snd_pcm_hw_params_any(pcm, hwparams) < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
- goto error;
- }
-
- /* Set the desired hardware parameters. */
-
- if (_use_mmap) {
-
- if (snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
-
- /* mmap() didn't work, fall back to interleaved */
-
- if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
- AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
- goto error;
- }
-
- _use_mmap = 0;
- }
-
- } else if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
- AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
- goto error;
- }
- AUDIO_LOG_DEBUG("setting rate - %d", sample_spec->rate);
- err = snd_pcm_hw_params_set_rate(pcm, hwparams, sample_spec->rate, 0);
- if (err < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
- }
-
- err = snd_pcm_hw_params(pcm, hwparams);
- if (err < 0) {
- AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
- goto error;
- }
-
- /* Dump current param */
-
- if ((ret = snd_pcm_hw_params_current(pcm, hwparams)) < 0) {
- AUDIO_LOG_INFO("snd_pcm_hw_params_current() failed: %s", snd_strerror(ret));
- goto error;
- }
-
- if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
- (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
- AUDIO_LOG_INFO("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", snd_strerror(ret));
- goto error;
- }
-
- snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
- AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
-
- snd_pcm_hw_params_get_format(hwparams, &sample_spec->format);
- AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
- snd_pcm_format_name((snd_pcm_format_t)sample_spec->format),
- snd_pcm_format_description((snd_pcm_format_t)sample_spec->format));
-
- snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
- AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
- snd_pcm_subformat_name((snd_pcm_subformat_t)val),
- snd_pcm_subformat_description((snd_pcm_subformat_t)val));
-
- snd_pcm_hw_params_get_channels(hwparams, &channels);
- sample_spec->channels = (uint8_t)channels;
- AUDIO_LOG_DEBUG("channels = %d\n", sample_spec->channels);
-
- if (buffer_size)
- *buffer_size = _buffer_size;
-
- if (period_size)
- *period_size = _period_size;
-
- if (use_mmap)
- *use_mmap = _use_mmap;
-
- return AUDIO_RET_OK;
-
-error:
- return AUDIO_ERR_RESOURCE;
-}
-
-audio_return_t _audio_pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event)
-{
- snd_pcm_sw_params_t *swparams;
- snd_pcm_uframes_t boundary;
- int err;
-
- AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
-
- snd_pcm_sw_params_alloca(&swparams);
-
- if ((err = snd_pcm_sw_params_current(pcm, swparams)) < 0) {
- AUDIO_LOG_WARN("Unable to determine current swparams: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
- AUDIO_LOG_WARN("Unable to disable period event: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
- AUDIO_LOG_WARN("Unable to enable time stamping: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
- AUDIO_LOG_WARN("Unable to get boundary: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
- AUDIO_LOG_WARN("Unable to set stop threshold: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) avail_min)) < 0) {
- AUDIO_LOG_WARN("Unable to set start threshold: %s\n", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
- AUDIO_LOG_WARN("snd_pcm_sw_params_set_avail_min() failed: %s", snd_strerror(err));
- goto error;
- }
- if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
- AUDIO_LOG_WARN("Unable to set sw params: %s\n", snd_strerror(err));
- goto error;
- }
- return AUDIO_RET_OK;
-error:
- return err;
-}
-
/* ------ dump helper -------- */
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-dump_data_t* dump_new(int length)
+dump_data_t* _audio_dump_new(int length)
{
dump_data_t* dump = NULL;
return dump;
}
-void dump_add_str(dump_data_t *dump, const char *fmt, ...)
+void _audio_dump_add_str(dump_data_t *dump, const char *fmt, ...)
{
int len;
va_list ap;
dump->left -= MAX(0, len);
}
-char* dump_get_str(dump_data_t *dump)
+char* _audio_dump_get_str(dump_data_t *dump)
{
return (dump) ? dump->strbuf : NULL;
}
-void dump_free(dump_data_t *dump)
+void _audio_dump_free(dump_data_t *dump)
{
if (dump) {
if (dump->strbuf)
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "tizen-audio-internal.h"
-/* audio latency */
-static const char* AUDIO_LATENCY_LOW = "low";
-static const char* AUDIO_LATENCY_MID = "mid";
-static const char* AUDIO_LATENCY_HIGH = "high";
-static const char* AUDIO_LATENCY_VOIP = "voip";
-
-audio_return_t audio_add_message_cb(void *audio_handle, message_cb callback, void *user_data)
-{
- audio_return_t ret = AUDIO_RET_OK;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
-
- /* NOTE: Management of several callbacks could be implemented.
- But we do not care of it for now.*/
- ret = _audio_comm_set_message_callback((audio_hal_t *)audio_handle, callback, user_data);
-
- return ret;
-}
-
-audio_return_t audio_remove_message_cb(void *audio_handle, message_cb callback)
-{
- audio_return_t ret = AUDIO_RET_OK;
-
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(callback, AUDIO_ERR_PARAMETER);
-
- ret = _audio_comm_unset_message_callback((audio_hal_t *)audio_handle);
-
- return ret;
-}
-
audio_return_t audio_init(void **audio_handle)
{
audio_hal_t *ah;
AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
if (!(ah = malloc(sizeof(audio_hal_t)))) {
- AUDIO_LOG_ERROR("am malloc failed");
+ AUDIO_LOG_ERROR("failed to malloc()");
return AUDIO_ERR_RESOURCE;
}
- if (AUDIO_IS_ERROR((ret = _audio_device_init(ah)))) {
- AUDIO_LOG_ERROR("device init failed");
+ if ((ret = _audio_volume_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_volume_init(), ret(0x%x)", ret);
goto error_exit;
}
- if (AUDIO_IS_ERROR((ret = _audio_volume_init(ah)))) {
- AUDIO_LOG_ERROR("stream init failed");
+ if ((ret = _audio_routing_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_routing_init(), ret(0x%x)", ret);
goto error_exit;
}
- if (AUDIO_IS_ERROR((ret = _audio_ucm_init(ah)))) {
- AUDIO_LOG_ERROR("ucm init failed");
+ if ((ret = _audio_stream_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_stream_init(), ret(0x%x)", ret);
goto error_exit;
}
- if (AUDIO_IS_ERROR((ret = _audio_util_init(ah)))) {
- AUDIO_LOG_ERROR("mixer init failed");
+ if ((ret = _audio_pcm_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_pcm_init(), ret(0x%x)", ret);
goto error_exit;
}
- if (AUDIO_IS_ERROR((ret = _audio_modem_init(ah)))) {
- AUDIO_LOG_ERROR("modem init failed");
+ if ((ret = _audio_modem_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_modem_init(), ret(0x%x)", ret);
goto error_exit;
}
- if (AUDIO_IS_ERROR((ret = _audio_comm_init(ah)))) {
- AUDIO_LOG_ERROR("comm init failed");
+ if ((ret = _audio_comm_init(ah))) {
+ AUDIO_LOG_ERROR("failed to _audio_comm_init(), ret(0x%x)", ret);
goto error_exit;
}
AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
- _audio_device_deinit(ah);
_audio_volume_deinit(ah);
- _audio_ucm_deinit(ah);
- _audio_util_deinit(ah);
+ _audio_routing_deinit(ah);
+ _audio_stream_deinit(ah);
+ _audio_pcm_deinit(ah);
_audio_modem_deinit(ah);
_audio_comm_deinit(ah);
free(ah);
ah = NULL;
return AUDIO_RET_OK;
-}
-
-/* Latency msec */
-static const unsigned int PERIOD_TIME_FOR_ULOW_LATENCY_MSEC = 20;
-static const unsigned int PERIOD_TIME_FOR_LOW_LATENCY_MSEC = 25;
-static const unsigned int PERIOD_TIME_FOR_MID_LATENCY_MSEC = 50;
-static const unsigned int PERIOD_TIME_FOR_HIGH_LATENCY_MSEC = 75;
-static const unsigned int PERIOD_TIME_FOR_UHIGH_LATENCY_MSEC = 150;
-static const unsigned int PERIOD_TIME_FOR_VOIP_LATENCY_MSEC = 20;
-
-static const uint32_t g_size_table[] = {
- [AUDIO_SAMPLE_U8] = 1,
- [AUDIO_SAMPLE_ULAW] = 1,
- [AUDIO_SAMPLE_ALAW] = 1,
- [AUDIO_SAMPLE_S16LE] = 2,
- [AUDIO_SAMPLE_S16BE] = 2,
- [AUDIO_SAMPLE_FLOAT32LE] = 4,
- [AUDIO_SAMPLE_FLOAT32BE] = 4,
- [AUDIO_SAMPLE_S32LE] = 4,
- [AUDIO_SAMPLE_S32BE] = 4,
- [AUDIO_SAMPLE_S24LE] = 3,
- [AUDIO_SAMPLE_S24BE] = 3,
- [AUDIO_SAMPLE_S24_32LE] = 4,
- [AUDIO_SAMPLE_S24_32BE] = 4
-};
-
-int _sample_spec_valid(uint32_t rate, audio_sample_format_t format, uint32_t channels)
-{
- if ((rate <= 0 ||
- rate > (48000U*4U) ||
- channels <= 0 ||
- channels > 32U ||
- format >= AUDIO_SAMPLE_MAX ||
- format < AUDIO_SAMPLE_U8))
- return 0;
-
- AUDIO_LOG_ERROR("hal-latency - _sample_spec_valid() -> return true");
-
- return 1;
-}
-
-uint32_t _audio_usec_to_bytes(uint64_t t, uint32_t rate, audio_sample_format_t format, uint32_t channels)
-{
- uint32_t ret = (uint32_t) (((t * rate) / 1000000ULL)) * (g_size_table[format] * channels);
- AUDIO_LOG_DEBUG("hal-latency - return %d", ret);
- return ret;
-}
-
-uint32_t _audio_sample_size(audio_sample_format_t format)
-{
- return g_size_table[format];
-}
-audio_return_t audio_get_buffer_attr(void *audio_handle,
- uint32_t direction,
- const char *latency,
- uint32_t samplerate,
- audio_sample_format_t format,
- uint32_t channels,
- uint32_t *maxlength,
- uint32_t *tlength,
- uint32_t *prebuf,
- uint32_t *minreq,
- uint32_t *fragsize)
-{
- AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(latency, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(maxlength, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(tlength, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(prebuf, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(minreq, AUDIO_ERR_PARAMETER);
- AUDIO_RETURN_VAL_IF_FAIL(fragsize, AUDIO_ERR_PARAMETER);
-
- AUDIO_LOG_DEBUG("hal-latency - audio_get_buffer_attr(direction:%d, latency:%s, samplerate:%d, format:%d, channels:%d)", direction, latency, samplerate, format, channels);
-
- uint32_t period_time = 0,
- sample_per_period = 0;
-
- if (_sample_spec_valid(samplerate, format, channels) == 0) {
- return AUDIO_ERR_PARAMETER;
- }
-
- if (direction == AUDIO_DIRECTION_IN) {
- if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_LOW");
- period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = -1;
- *maxlength = -1;
- *fragsize = sample_per_period * _audio_sample_size(format);
- } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_MID");
- period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = -1;
- *maxlength = -1;
- *fragsize = sample_per_period * _audio_sample_size(format);
- } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_HIGH");
- period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = -1;
- *maxlength = -1;
- *fragsize = sample_per_period * _audio_sample_size(format);
- } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_IN, AUDIO_LATENCY_VOIP");
- period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = -1;
- *maxlength = -1;
- *fragsize = sample_per_period * _audio_sample_size(format);
- } else {
- AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
- return AUDIO_ERR_UNDEFINED;
- }
- } else { /* AUDIO_DIRECTION_OUT */
- if (!strcmp(latency, AUDIO_LATENCY_LOW)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_LOW");
- period_time = PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = (samplerate / 10) * _audio_sample_size(format) * channels; /* 100ms */
- *maxlength = -1;
- *fragsize = 0;
- } else if (!strcmp(latency, AUDIO_LATENCY_MID)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_MID");
- period_time = PERIOD_TIME_FOR_MID_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = (uint32_t) _audio_usec_to_bytes(200000, samplerate, format, channels);
- *maxlength = -1;
- *fragsize = -1;
- } else if (!strcmp(latency, AUDIO_LATENCY_HIGH)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_HIGH");
- period_time = PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = -1;
- *tlength = (uint32_t) _audio_usec_to_bytes(400000, samplerate, format, channels);
- *maxlength = -1;
- *fragsize = -1;
- } else if (!strcmp(latency, AUDIO_LATENCY_VOIP)) {
- AUDIO_LOG_DEBUG("AUDIO_DIRECTION_OUT, AUDIO_LATENCY_VOIP");
- period_time = PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
- sample_per_period = (samplerate * period_time) / 1000;
- *prebuf = 0;
- *minreq = _audio_usec_to_bytes(20000, samplerate, format, channels);
- *tlength = _audio_usec_to_bytes(100000, samplerate, format, channels);
- *maxlength = -1;
- *fragsize = 0;
- } else {
- AUDIO_LOG_ERROR("hal-latency - The latency(%s) is undefined", latency);
- return AUDIO_ERR_UNDEFINED;
- }
- }
-
- AUDIO_LOG_INFO("hal-latency - return attr --> prebuf:%d, minreq:%d, tlength:%d, maxlength:%d, fragsize:%d", *prebuf, *minreq, *tlength, *maxlength, *fragsize);
- return AUDIO_RET_OK;
-}
+}
\ No newline at end of file
/*
* audio-hal
*
- * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdint.h>
/* Error code */
-#define AUDIO_IS_ERROR(ret) (ret < 0)
typedef enum audio_return {
AUDIO_RET_OK = 0,
AUDIO_ERR_UNDEFINED = (int32_t)0x80001000,
audio_return_t (*update_route_option)(void *audio_handle, audio_route_option_t *option);
/* Stream */
audio_return_t (*notify_stream_connection_changed)(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected);
- /* Buffer attribute */
audio_return_t (*get_buffer_attr)(void *audio_handle, uint32_t direction, const char *latency, uint32_t samplerate, int format, uint32_t channels,
uint32_t *maxlength, uint32_t *tlength, uint32_t *prebuf, uint32_t* minreq, uint32_t *fragsize);
- /* PCM device */
+ /* PCM */
audio_return_t (*pcm_open)(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
audio_return_t (*pcm_start)(void *audio_handle, void *pcm_handle);
audio_return_t (*pcm_stop)(void *audio_handle, void *pcm_handle);