/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "alsa.h" BOOL alsa_get_device_name(int index, char * filename, int len) { int card = -1, count = 0, ret; snd_ctl_card_info_t * info; snd_ctl_card_info_alloca(&info); ret = snd_card_next(&card); while (ret == 0 && card != -1) { char name[16]; snd_ctl_t * ctl; snprintf(name, sizeof(name), "hw:%d", card); if (snd_ctl_open(&ctl, name, SND_CTL_NONBLOCK) < 0) { ret = snd_card_next(&card); continue; } if (snd_ctl_card_info(ctl, info) < 0) { snd_ctl_close(ctl); ret = snd_card_next(&card); continue; } snd_ctl_close(ctl); if (index == count) { strncpy(filename, name, len); return TRUE; } ret = snd_card_next(&card); } return FALSE; } BOOL alsa_open_device(ALSACTX * p_alsa, snd_pcm_stream_t mode, uint32 * sample_rate, int channels) { int res, flags; snd_pcm_format_t format; snd_pcm_t *h; snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t buffer_size, period_size = 0; if (NULL == p_alsa) { return FALSE; } flags = SND_PCM_NONBLOCK; format = SND_PCM_FORMAT_S16_LE; p_alsa->framesize = 16 / 8 * channels; res = snd_pcm_open(&h, p_alsa->devname, mode, flags); if (res < 0) { log_print(HT_LOG_ERR, "cannot open audio device %s (%s)\r\n", p_alsa->devname, snd_strerror(res)); return FALSE; } snd_pcm_hw_params_alloca(&hw_params); res = snd_pcm_hw_params_any(h, hw_params); if (res < 0) { log_print(HT_LOG_ERR, "cannot initialize hardware parameter structure (%s)\r\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_access(h, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (res < 0) { log_print(HT_LOG_ERR, "cannot set access type (%s)\r\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_format(h, hw_params, format); if (res < 0) { log_print(HT_LOG_ERR, "cannot set sample format %d (%s)\r\n", format, snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_rate_near(h, hw_params, sample_rate, 0); if (res < 0) { log_print(HT_LOG_ERR, "cannot set sample rate (%s)\r\n", snd_strerror(res)); goto fail; } res = snd_pcm_hw_params_set_channels(h, hw_params, channels); if (res < 0) { log_print(HT_LOG_ERR, "cannot set channel count to %d (%s)\r\n", channels, snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size); buffer_size = (buffer_size > ALSA_BUFFER_SIZE_MAX ? ALSA_BUFFER_SIZE_MAX : buffer_size); res = snd_pcm_hw_params_set_buffer_size_near(h, hw_params, &buffer_size); if (res < 0) { log_print(HT_LOG_ERR, "cannot set ALSA buffer size (%s)\r\n", snd_strerror(res)); goto fail; } snd_pcm_hw_params_get_period_size_min(hw_params, &period_size, NULL); if (!period_size) { period_size = buffer_size / 4; } if (period_size < 64) { period_size = 64; } res = snd_pcm_hw_params_set_period_size_near(h, hw_params, &period_size, NULL); if (res < 0) { log_print(HT_LOG_ERR, "cannot set ALSA period size (%s)\r\n", snd_strerror(res)); goto fail; } p_alsa->period_size = period_size; res = snd_pcm_hw_params(h, hw_params); if (res < 0) { log_print(HT_LOG_ERR, "cannot set parameters (%s)\r\n", snd_strerror(res)); goto fail; } p_alsa->handler = h; return TRUE; fail: snd_pcm_close(h); return FALSE; } void alsa_close_device(ALSACTX * p_alsa) { if (p_alsa->handler) { if (snd_pcm_stream(p_alsa->handler) == SND_PCM_STREAM_PLAYBACK) { snd_pcm_nonblock(p_alsa->handler, 0); snd_pcm_drain(p_alsa->handler); } snd_pcm_close(p_alsa->handler); p_alsa->handler = NULL; } } int alsa_xrun_recover(snd_pcm_t * handler, int err) { if (err == -EPIPE) { err = snd_pcm_prepare(handler); if (err < 0) { log_print(HT_LOG_ERR, "snd_pcm_prepare failed: %s\r\n", snd_strerror(err)); } else { return 0; } } else if (err == -ESTRPIPE) { log_print(HT_LOG_ERR, "-ESTRPIPE... Unsupported!\n"); } return err; }