From: Jaechul Lee Date: Mon, 25 Apr 2022 05:06:26 +0000 (+0900) Subject: Change set_rate/set_channels to set_rate_near/set_channels_near X-Git-Tag: submit/tizen/20220627.045454^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=81f1b82b5fd332f6b639ec6b4234fa3d2cff2add;p=platform%2Fadaptation%2Fap_broadcom%2Faudio-hal-bcm2837.git Change set_rate/set_channels to set_rate_near/set_channels_near It tries to open a device by _near APIs in order to support USB devices. [Version] 0.1.17 [Issue Type] New feature Change-Id: Ib9c8b93cc1b7b2a40026c183de3e1ef3575ea607 Signed-off-by: Jaechul Lee --- diff --git a/packaging/audio-hal-bcm2837.spec b/packaging/audio-hal-bcm2837.spec index 05cdd6f..52e5a1f 100644 --- a/packaging/audio-hal-bcm2837.spec +++ b/packaging/audio-hal-bcm2837.spec @@ -1,6 +1,6 @@ Name: audio-hal-bcm2837 Summary: TIZEN Audio HAL for BCM2837 -Version: 0.1.16 +Version: 0.1.17 Release: 0 Group: System/Libraries License: Apache-2.0 diff --git a/tizen-audio-impl-pcm.c b/tizen-audio-impl-pcm.c index 3a7b970..5c26dbe 100644 --- a/tizen-audio-impl-pcm.c +++ b/tizen-audio-impl-pcm.c @@ -32,40 +32,11 @@ #define DEVICE_NAME_MAX 32 #endif -#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__ /* 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_s format) -{ - return g_format_convert_table[format]; -} - /* #define DEBUG_TIMING */ #ifdef __USE_TINYALSA__ @@ -170,9 +141,7 @@ audio_return_e _pcm_open(const char *card, const char *device, uint32_t directio #ifdef __USE_TINYALSA__ audio_pcm_sample_spec_s *ss; - ss = (audio_pcm_sample_spec_s *)sample_spec; - ss->format = __convert_format((audio_sample_format_s)ss->format); - + 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"); @@ -459,7 +428,7 @@ audio_return_e _pcm_recover(void *pcm_handle, int revents) return AUDIO_RET_OK; } -audio_return_e _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_s *ss; @@ -467,7 +436,7 @@ audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp unsigned int _start_threshold, _stop_threshold, _silence_threshold; struct pcm_config *config; - ss = (audio_pcm_sample_spec_s *)*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); @@ -486,7 +455,7 @@ audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp 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_s *ss; + audio_pcm_sample_spec_s ss; int dir; snd_pcm_uframes_t _period_size, _buffer_size; snd_pcm_format_t _format; @@ -496,8 +465,6 @@ audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; - ss = (audio_pcm_sample_spec_s *)*sample_spec; - snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); @@ -518,9 +485,11 @@ audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp *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); @@ -535,12 +504,46 @@ audio_return_e _pcm_get_params(void *pcm_handle, uint32_t direction, void **samp } AUDIO_LOG_DEBUG("_pcm_get_params (handle %p, format %d, rate %u, channels %u, period_size %lu, periods %u, buffer_size %lu)", - pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size); + pcm_handle, ss.format, ss.rate, ss.channels, _period_size, _periods, _buffer_size); #endif return AUDIO_RET_OK; } +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__ @@ -548,16 +551,24 @@ audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl AUDIO_LOG_DEBUG("_pcm_set_params"); #else /* alsa-lib */ int err; - audio_pcm_sample_spec_s ss; - snd_pcm_uframes_t _buffer_size; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; - ss = *(audio_pcm_sample_spec_s *)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); @@ -574,38 +585,64 @@ audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl return AUDIO_ERR_PARAMETER; } - ss.format = __convert_format((audio_sample_format_s)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 = _period_size = selected_ss.rate * period_size / requested_ss.rate; - 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); + 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 (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); - _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(%lu) failed : %d", _buffer_size, err); + period_size = period_size_near; + buffer_size = period_size * periods; + buffer_size_near = buffer_size; + + 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; @@ -627,7 +664,7 @@ audio_return_e _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, _buffer_size)) < 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; } @@ -648,8 +685,10 @@ audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sampl return AUDIO_ERR_IOCTL; } - AUDIO_LOG_DEBUG("_pcm_set_params (handle %p, format %d, rate %u, channels %u, period_size %u, periods %u, buffer_size %lu)", - 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; diff --git a/tizen-audio-impl.h b/tizen-audio-impl.h index 17b4025..42f93b3 100644 --- a/tizen-audio-impl.h +++ b/tizen-audio-impl.h @@ -30,7 +30,7 @@ audio_return_e _pcm_write(void *pcm_handle, const void *buffer, uint32_t frames) audio_return_e _pcm_read(void *pcm_handle, void *buffer, uint32_t frames); audio_return_e _pcm_get_fd(void *pcm_handle, int *fd); audio_return_e _pcm_recover(void *pcm_handle, int revents); -audio_return_e _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); audio_return_e _pcm_set_params(void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods); audio_return_e _pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event); 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); diff --git a/tizen-audio-internal.h b/tizen-audio-internal.h index 604d7a1..d1312bb 100644 --- a/tizen-audio-internal.h +++ b/tizen-audio-internal.h @@ -253,6 +253,9 @@ audio_return_e _audio_comm_init(audio_hal_s *ah); audio_return_e _audio_comm_deinit(audio_hal_s *ah); audio_return_e _audio_comm_send_message(audio_hal_s *ah, const char *name, int value); +void convert_hal_format_from_sample_spec(void *src, audio_pcm_sample_spec_s *dst); +void convert_hal_format_to_sample_spec(audio_pcm_sample_spec_s *src, void *dst); + typedef struct _dump_data { char *strbuf; int left; diff --git a/tizen-audio-pcm.c b/tizen-audio-pcm.c index c4f2982..7759bb6 100644 --- a/tizen-audio-pcm.c +++ b/tizen-audio-pcm.c @@ -161,7 +161,7 @@ audio_return_e audio_pcm_recover(void *audio_handle, void *pcm_handle, int reven return audio_ret; } -audio_return_e 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_e 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_e audio_ret = AUDIO_RET_OK; diff --git a/tizen-audio-util.c b/tizen-audio-util.c index 6ab4aa0..0d1326b 100644 --- a/tizen-audio-util.c +++ b/tizen-audio-util.c @@ -24,12 +24,97 @@ #include #include #include +#include #include "tizen-audio-internal.h" /* ------ dump helper -------- */ #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#ifdef __USE_TINYALSA__ +static const uint32_t g_format_convert_hal_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 +}; + +static const uint32_t g_format_convert_native_table[] = { + [PCM_FORMAT_S8] = AUDIO_SAMPLE_U8, + [PCM_FORMAT_S16_LE] = AUDIO_SAMPLE_S16LE, + [PCM_FORMAT_S32_LE] = AUDIO_SAMPLE_S32LE, + [PCM_FORMAT_S24_LE] = AUDIO_SAMPLE_S24_32LE +}; +#else +static const uint32_t g_format_convert_hal_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 +}; + +static const snd_pcm_format_t g_format_convert_native_table[] = { + [SND_PCM_FORMAT_U8] = AUDIO_SAMPLE_U8, + [SND_PCM_FORMAT_A_LAW] = AUDIO_SAMPLE_ALAW, + [SND_PCM_FORMAT_MU_LAW] = AUDIO_SAMPLE_ULAW, + [SND_PCM_FORMAT_S16_LE] = AUDIO_SAMPLE_S16LE, + [SND_PCM_FORMAT_S16_BE] = AUDIO_SAMPLE_S16BE, + [SND_PCM_FORMAT_FLOAT_LE] = AUDIO_SAMPLE_FLOAT32LE, + [SND_PCM_FORMAT_FLOAT_BE] = AUDIO_SAMPLE_FLOAT32BE, + [SND_PCM_FORMAT_S32_LE] = AUDIO_SAMPLE_S32LE, + [SND_PCM_FORMAT_S32_BE] = AUDIO_SAMPLE_S32BE, + [SND_PCM_FORMAT_S24_3LE] = AUDIO_SAMPLE_S24LE, + [SND_PCM_FORMAT_S24_3BE] = AUDIO_SAMPLE_S24BE, + [SND_PCM_FORMAT_S24_LE] = AUDIO_SAMPLE_S24_32LE, + [SND_PCM_FORMAT_S24_BE] = AUDIO_SAMPLE_S24_32BE +}; +#endif + +static snd_pcm_format_t __convert_to_hal_format(audio_sample_format_s format) +{ + return g_format_convert_hal_table[format]; +} + +static uint32_t __convert_to_native_format(snd_pcm_format_t format) +{ + return g_format_convert_native_table[format]; +} + +/* src is pa_sample_spec which pulseaudio uses */ +void convert_hal_format_from_sample_spec(void *src, audio_pcm_sample_spec_s *dst) +{ + audio_sample_format_s format; + + assert(src); + assert(dst); + + memcpy(dst, src, sizeof(audio_pcm_sample_spec_s)); + + format = ((audio_pcm_sample_spec_s *)src)->format; + + dst->format = __convert_to_hal_format(format); +} + +/* dst is pa_sample_spec which pulseaudio uses */ +void convert_hal_format_to_sample_spec(audio_pcm_sample_spec_s *src, void *dst) +{ + assert(src); + assert(dst); + + memcpy(dst, src, sizeof(audio_pcm_sample_spec_s)); + + ((audio_pcm_sample_spec_s *)dst)->format = __convert_to_native_format(src->format); +} + dump_data_t* _audio_dump_new(int length) { dump_data_t* dump = NULL; diff --git a/tizen-audio.h b/tizen-audio.h index 52ed4cb..15ee937 100644 --- a/tizen-audio.h +++ b/tizen-audio.h @@ -378,7 +378,7 @@ audio_return_e audio_pcm_recover(void *audio_handle, void *pcm_handle, int reven * @retval #AUDIO_RET_OK Success * @see audio_pcm_set_params() */ -audio_return_e 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_e audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t *period_size, uint32_t *periods); /** * @brief Sets hardware and software parameters of a PCM device.