Fix coverity issues (PROC_USE.VULNERABLE)
[platform/adaptation/emulator/audio-hal-emul.git] / tizen-audio-impl-pcm.c
index 57229c8..59b6360 100644 (file)
 #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 */
+#ifndef __USE_TINYALSA__
+#define DEVICE_NAME_MAX 32
+#endif
+
+#ifndef __USE_TINYALSA__
 /* 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];
+#ifdef __USE_TINYALSA__
+static int __parse_card_device_number(const char *card, const char *device, unsigned int *card_u, unsigned int *device_u) {
+    AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(card_u, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(device_u, AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_DEBUG("card : %s, device : %s", card, device);
+
+    *card_u = (unsigned int) strtol(card, NULL, 10);
+    *device_u = (unsigned int) strtol(device, NULL, 10);
+
+    return 0;
 }
 
-#ifdef __USE_TINYALSA__
-static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t period_size, size_t period_count, uint32_t direction)
+static struct pcm *__tinyalsa_open_device(const char *card, const char *device, audio_pcm_sample_spec_s *ss, size_t period_size, size_t period_count, uint32_t direction)
 {
     struct pcm *pcm = NULL;
     struct pcm_config config;
+    unsigned int card_u, device_u;
 
+    AUDIO_RETURN_NULL_IF_FAIL(device);
     AUDIO_RETURN_NULL_IF_FAIL(ss);
 
     config.channels          = ss->channels;
@@ -80,12 +70,15 @@ static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t pe
     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);
+    AUDIO_LOG_INFO("card %s, device %s, direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d",
+        card, device, direction, ss->channels, ss->rate, ss->format, period_size, period_count);
+
+    if (__parse_card_device_number(card, device, &card_u, &device_u) < 0) {
+        AUDIO_LOG_ERROR("Failed to get card device number from %s", device);
+        return NULL;
+    }
 
-    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);
+    pcm = pcm_open(card_u, device_u, (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);
@@ -119,16 +112,35 @@ static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
 }
 #endif
 
-audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
+#ifndef __USE_TINYALSA__
+static int __make_alsa_device_name(const char *card, const char *device, char device_name[])
+{
+    AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(device_name, AUDIO_ERR_PARAMETER);
+
+    snprintf(device_name, DEVICE_NAME_MAX, "hw:%s,%s", card, device);
+    return 0;
+}
+#endif
+
+audio_return_e _pcm_open(const char *card, const char *device, uint32_t direction, void *sample_spec,
+        uint32_t period_size, uint32_t periods, void **pcm_handle)
 {
-#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);
+    AUDIO_RETURN_VAL_IF_FAIL(card, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(device, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL((direction == AUDIO_DIRECTION_OUT) || (direction == AUDIO_DIRECTION_IN),
+                            AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_INFO("card(%s) device(%s) direction(%u) period_size(%u) periods(%u)",
+                    card, device, direction, period_size, periods);
+#ifdef __USE_TINYALSA__
+    audio_pcm_sample_spec_s *ss;
 
-    *pcm_handle = __tinyalsa_open_device(ss, (size_t)period_size, (size_t)periods, direction);
+    convert_hal_format_from_sample_spec(sample_spec, &ss);
+    *pcm_handle = __tinyalsa_open_device(card, 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;
@@ -139,28 +151,21 @@ audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spe
     }
 
 #else  /* alsa-lib */
-    int err, mode;
-    char *device_name = NULL;
+    int mode;
+    audio_return_e ret;
+    char device_name[DEVICE_NAME_MAX];
 
+    __make_alsa_device_name(card, device, device_name);
     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;
+    if ((ret = _pcm_set_params(*pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
+        AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", ret);
+        return ret;
     }
 
     AUDIO_LOG_INFO("PCM device %s", device_name);
@@ -169,7 +174,7 @@ audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spe
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_start(void *pcm_handle)
+audio_return_e _pcm_start(void *pcm_handle)
 {
     int err;
 
@@ -185,11 +190,11 @@ audio_return_t _pcm_start(void *pcm_handle)
     }
 #endif
 
-    AUDIO_LOG_INFO("PCM handle 0x%x start", pcm_handle);
+    AUDIO_LOG_INFO("PCM handle %p start", pcm_handle);
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_stop(void *pcm_handle)
+audio_return_e _pcm_stop(void *pcm_handle)
 {
     int err;
 
@@ -205,15 +210,15 @@ audio_return_t _pcm_stop(void *pcm_handle)
     }
 #endif
 
-    AUDIO_LOG_INFO("PCM handle 0x%x stop", pcm_handle);
+    AUDIO_LOG_INFO("PCM handle %p stop", pcm_handle);
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_close(void *pcm_handle)
+audio_return_e _pcm_close(void *pcm_handle)
 {
     int err;
 
-    AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
+    AUDIO_LOG_INFO("Try to close PCM handle %p", pcm_handle);
 
 #ifdef __USE_TINYALSA__
     if ((err = pcm_close(pcm_handle)) < 0) {
@@ -230,7 +235,7 @@ audio_return_t _pcm_close(void *pcm_handle)
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail)
+audio_return_e _pcm_avail(void *pcm_handle, uint32_t *avail)
 {
 #ifdef __USE_TINYALSA__
     struct timespec tspec;
@@ -239,7 +244,7 @@ audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail)
 
     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);
+        AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle %p : %d", pcm_handle, err);
         return AUDIO_ERR_IOCTL;
     }
 
@@ -252,7 +257,7 @@ audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail)
     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);
+        AUDIO_LOG_ERROR("Could not get avail at PCM handle %p : %ld", pcm_handle, frames_avail);
         return AUDIO_ERR_IOCTL;
     }
 
@@ -266,7 +271,7 @@ audio_return_t _pcm_avail(void *pcm_handle, uint32_t *avail)
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
+audio_return_e _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
 {
 #ifdef __USE_TINYALSA__
     int err;
@@ -287,7 +292,7 @@ audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
 
     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);
+        AUDIO_LOG_ERROR("Failed to write pcm : %ld", frames_written);
         return AUDIO_ERR_IOCTL;
     }
 
@@ -299,7 +304,7 @@ audio_return_t _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames)
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
+audio_return_e _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
 {
 #ifdef __USE_TINYALSA__
     int err;
@@ -318,7 +323,7 @@ audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
 
     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);
+        AUDIO_LOG_ERROR("Failed to read pcm : %ld", frames_read);
         return AUDIO_ERR_IOCTL;
     }
 
@@ -330,7 +335,7 @@ audio_return_t _pcm_read(void *pcm_handle, void *buffer, uint32_t frames)
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_get_fd(void *pcm_handle, int *fd)
+audio_return_e _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__
@@ -341,7 +346,7 @@ audio_return_t _pcm_get_fd(void *pcm_handle, int *fd)
     return AUDIO_RET_OK;
 }
 
-audio_return_t _pcm_recover(void *pcm_handle, int revents)
+audio_return_e _pcm_recover(void *pcm_handle, int revents)
 {
     int state, err;
 
@@ -421,15 +426,15 @@ audio_return_t _pcm_recover(void *pcm_handle, int revents)
     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)
+audio_return_e _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;
+    audio_pcm_sample_spec_s *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;
+    ss = (audio_pcm_sample_spec_s *)sample_spec;
 
     /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
     _pcm_config(pcm_handle, &config);
@@ -444,21 +449,20 @@ audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp
     _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);
+    AUDIO_LOG_DEBUG("_pcm_get_params (handle %p, format %d, rate %u, channels %u, period_size %u, periods %u, buffer_size %u)",
+                    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;
+    audio_pcm_sample_spec_ss;
     int dir;
-    snd_pcm_uframes_t _period_size, _buffer_size;
+    snd_pcm_uframes_t _period_size = 0 , _buffer_size = 0;
     snd_pcm_format_t _format;
-    unsigned int _rate, _channels;
-    snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
-    unsigned int _periods;
+    unsigned int _rate = 0, _channels = 0;
+    snd_pcm_uframes_t _start_threshold = 0, _stop_threshold = 0, _silence_threshold = 0, _avail_min = 0;
+    unsigned int _periods = 0;
     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);
 
@@ -473,15 +477,17 @@ audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp
         (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);
+        AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %d", err);
         return AUDIO_ERR_PARAMETER;
     }
 
     *period_size = _period_size;
     *periods     = _periods;
-    ss->format   = _format;
-    ss->rate     = _rate;
-    ss->channels = _channels;
+
+    ss.rate = _rate;
+    ss.channels = _channels;
+    ss.format = _format;
+    convert_hal_format_to_sample_spec(&ss, sample_spec);
 
     if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
@@ -492,32 +498,76 @@ audio_return_t _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp
         (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_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %d", 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);
+    AUDIO_LOG_DEBUG("_pcm_get_params (handle %p, format %d, rate %u, channels %u, period_size %lu, periods %u, buffer_size %lu,",
+                    pcm_handle, ss.format, ss.rate, ss.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)
+static int __set_format(void *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_format_t *format)
+{
+    const snd_pcm_format_t formats[] = {
+        SND_PCM_FORMAT_U8,
+        SND_PCM_FORMAT_A_LAW,
+        SND_PCM_FORMAT_MU_LAW,
+        SND_PCM_FORMAT_S16_LE,
+        SND_PCM_FORMAT_S16_BE,
+        SND_PCM_FORMAT_FLOAT_LE,
+        SND_PCM_FORMAT_FLOAT_BE,
+        SND_PCM_FORMAT_S32_LE,
+        SND_PCM_FORMAT_S32_BE,
+        SND_PCM_FORMAT_S24_3LE,
+        SND_PCM_FORMAT_S24_3BE,
+        SND_PCM_FORMAT_S24_LE,
+        SND_PCM_FORMAT_S24_BE,
+    };
+    int i;
+
+    if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, *format) >= 0)
+        return 0;
+
+    /* Try to find appropriate format */
+    for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
+        if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, formats[i]) >= 0) {
+            *format = formats[i];
+            AUDIO_LOG_INFO("Selected proper format automatically. format(%d)", formats[i]);
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+audio_return_e _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_uframes_t period_size_near;
+    snd_pcm_uframes_t buffer_size;
+    snd_pcm_uframes_t buffer_size_near;
+    audio_pcm_sample_spec_s requested_ss;
+    audio_pcm_sample_spec_s selected_ss;
+    unsigned int ch;
 
     snd_pcm_hw_params_alloca(&hwparams);
     snd_pcm_sw_params_alloca(&swparams);
 
+    convert_hal_format_from_sample_spec(sample_spec, &requested_ss);
+    convert_hal_format_from_sample_spec(sample_spec, &selected_ss);
+
+    ch = selected_ss.channels;
+
     /* 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);
@@ -534,38 +584,64 @@ audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl
         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);
+    if ((err = __set_format(pcm_handle, hwparams, &selected_ss.format) < 0)) {
+        AUDIO_LOG_ERROR("Failed to set format.");
         return AUDIO_ERR_PARAMETER;
     }
 
-    if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
+    if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &selected_ss.rate, NULL)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
         return AUDIO_ERR_PARAMETER;
     }
 
-    if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
-        AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", ss.channels, err);
+    if ((err = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &ch)) < 0) {
+        AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", selected_ss.channels, err);
         return AUDIO_ERR_PARAMETER;
     }
+    selected_ss.channels = ch;
+
+    if (requested_ss.rate != selected_ss.rate ||
+        requested_ss.format != selected_ss.format ||
+        requested_ss.channels != selected_ss.channels) {
+
+        uint32_t _period_size = selected_ss.rate * period_size / requested_ss.rate;
+
+        AUDIO_LOG_INFO("hwparam has been changed. rate(%d->%d), channels(%d->%d), format(%d->%d)",
+                        requested_ss.rate, selected_ss.rate,
+                        requested_ss.channels, selected_ss.channels,
+                        requested_ss.format, selected_ss.format);
+
+        AUDIO_LOG_INFO("period_size must be calculated appropriately. period_size(%d->%d)",
+                        period_size, _period_size);
+
+        period_size = _period_size;
+    }
 
-    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", period_size, err);
+    if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL) < 0) {
+        AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods_near 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);
+    period_size_near = period_size;
+    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size_near, NULL) < 0) {
+        AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size_near(%u) failed : %d", period_size, err);
         return AUDIO_ERR_PARAMETER;
     }
+    AUDIO_LOG_INFO("requested period_size(%d). set period_size_near(%ld)", period_size, period_size_near);
+
+    period_size = period_size_near;
+    buffer_size = period_size * periods;
+    buffer_size_near = buffer_size;
 
-    _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);
+    if ((err = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size_near)) < 0) {
+        AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size_near(%lu) failed : %d", buffer_size, err);
         return AUDIO_ERR_PARAMETER;
     }
 
+    AUDIO_LOG_INFO("requested buffer_size(%lu). set buffer_size(%lu)", buffer_size, buffer_size_near);
+
+    buffer_size = buffer_size_near;
+
     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
         return AUDIO_ERR_IOCTL;
@@ -587,12 +663,12 @@ audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl
         return AUDIO_ERR_PARAMETER;
     }
 
-    if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, period_size / 2)) < 0) {
+    if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, buffer_size)) < 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) {
+    if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, period_size)) < 0) {
         AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
         return AUDIO_ERR_PARAMETER;
     }
@@ -608,16 +684,19 @@ audio_return_t _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl
         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);
+    convert_hal_format_to_sample_spec(&selected_ss, sample_spec);
+
+    AUDIO_LOG_DEBUG("_pcm_set_params (handle %p, format(%d), rate(%u), channels(%u), period_size(%u), periods(%u), buffer_size(%lu)",
+                    pcm_handle, selected_ss.format, selected_ss.rate, selected_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_e _pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_s *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;
+    audio_return_e ret = AUDIO_RET_OK;
     snd_pcm_hw_params_t *hwparams;
     int err = 0;
     int dir;
@@ -721,7 +800,7 @@ 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)
+audio_return_e _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;