215 lines
5.5 KiB
C++
215 lines
5.5 KiB
C++
|
|
/***************************************************************************************
|
||
|
|
*
|
||
|
|
* 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
|