From a188981a3682cc994e9c654cf0b68d45cd895e90 Mon Sep 17 00:00:00 2001 From: yangyalei Date: Tue, 13 Aug 2024 16:58:42 +0800 Subject: [PATCH] Alsa-lib: Add vela alsa lib interface Signed-off-by: yangyalei --- audioutils/alsa-lib/CMakeLists.txt | 23 + audioutils/alsa-lib/Kconfig | 16 + audioutils/alsa-lib/Make.defs | 28 + audioutils/alsa-lib/Makefile | 27 + audioutils/alsa-lib/alsa_error.c | 41 + audioutils/alsa-lib/alsa_pcm.c | 1209 ++++++++++++++++++++++ audioutils/alsa-lib/include/alsa_error.h | 44 + audioutils/alsa-lib/include/alsa_pcm.h | 444 ++++++++ audioutils/alsa-lib/include/asoundlib.h | 31 + 9 files changed, 1863 insertions(+) create mode 100644 audioutils/alsa-lib/CMakeLists.txt create mode 100644 audioutils/alsa-lib/Kconfig create mode 100644 audioutils/alsa-lib/Make.defs create mode 100644 audioutils/alsa-lib/Makefile create mode 100644 audioutils/alsa-lib/alsa_error.c create mode 100644 audioutils/alsa-lib/alsa_pcm.c create mode 100644 audioutils/alsa-lib/include/alsa_error.h create mode 100644 audioutils/alsa-lib/include/alsa_pcm.h create mode 100644 audioutils/alsa-lib/include/asoundlib.h diff --git a/audioutils/alsa-lib/CMakeLists.txt b/audioutils/alsa-lib/CMakeLists.txt new file mode 100644 index 0000000000..dcafdd5d12 --- /dev/null +++ b/audioutils/alsa-lib/CMakeLists.txt @@ -0,0 +1,23 @@ +# ############################################################################## +# apps/audioutils/alsa-lib/CMakeLists.txt +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you 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. +# +# ############################################################################## + +if(CONFIG_AUDIOUTILS_ALSA_LIB) + target_sources(apps PRIVATE alsa_pcm.c alsa_error.c) +endif() diff --git a/audioutils/alsa-lib/Kconfig b/audioutils/alsa-lib/Kconfig new file mode 100644 index 0000000000..ebfa3b0b71 --- /dev/null +++ b/audioutils/alsa-lib/Kconfig @@ -0,0 +1,16 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config AUDIOUTILS_ALSA_LIB + tristate "Enable ALSA lib" + default n + +if AUDIOUTILS_ALSA_LIB + +config AUDIOUTILS_ALSA_LIB_DEV_PATH + string "play/recored device path" + default "/dev/audio" + +endif # ALSA_LIB diff --git a/audioutils/alsa-lib/Make.defs b/audioutils/alsa-lib/Make.defs new file mode 100644 index 0000000000..97fec904c0 --- /dev/null +++ b/audioutils/alsa-lib/Make.defs @@ -0,0 +1,28 @@ +############################################################################ +# apps/audioutils/alsa-lib/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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. +# +############################################################################ + +ifneq ($(CONFIG_AUDIOUTILS_ALSA_LIB),) + +CONFIGURED_APPS += $(APPDIR)/audioutils/alsa-lib + +CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/audioutils/alsa-lib/include +CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/audioutils/alsa-lib/include + +endif diff --git a/audioutils/alsa-lib/Makefile b/audioutils/alsa-lib/Makefile new file mode 100644 index 0000000000..4c7108708a --- /dev/null +++ b/audioutils/alsa-lib/Makefile @@ -0,0 +1,27 @@ +############################################################################ +# apps/audioutils/alsa-lib/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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. +# +############################################################################ + +include $(APPDIR)/Make.defs + +CSRCS += $(wildcard *.c) + +EXPORT_FILES := include + +include $(APPDIR)/Application.mk diff --git a/audioutils/alsa-lib/alsa_error.c b/audioutils/alsa-lib/alsa_error.c new file mode 100644 index 0000000000..0682753708 --- /dev/null +++ b/audioutils/alsa-lib/alsa_error.c @@ -0,0 +1,41 @@ +/**************************************************************************** + * apps/audioutils/alsa-lib/alsa_error.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +FAR const char *snd_strerror(int errnum) +{ + if (errnum < 0) + { + errnum = -errnum; + } + + return (FAR const char *)strerror(errnum); +} diff --git a/audioutils/alsa-lib/alsa_pcm.c b/audioutils/alsa-lib/alsa_pcm.c new file mode 100644 index 0000000000..99d3d3dec1 --- /dev/null +++ b/audioutils/alsa-lib/alsa_pcm.c @@ -0,0 +1,1209 @@ +/**************************************************************************** + * apps/audioutils/alsa-lib/alsa_pcm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +#define DEFAULT_AUDIO_PERIODS 4 +#define DEFAULT_AUDIO_PERIOD_TIME 10 * 1000 + +#define FFMIN(a, b) ((a) > (b) ? (b) : (a)) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct _snd_pcm +{ + int fd; /* File descriptor of active device */ + mqd_t mq; /* Message queue for the playthread */ + char mqname[32]; /* Name of our message queue */ + char devname[32]; /* Preferred audio device */ + snd_pcm_stream_t stream; + + int volume; /* Volume as a whole percentage (0-100) */ + snd_pcm_format_t format; + unsigned int channels; + int sample_bytes; /* bytes per sample * channels */ + unsigned int sample_rate; + + int periods; + int period_time; /* us */ + snd_pcm_uframes_t period_size; + + snd_pcm_uframes_t start_threshold; /* auto start with frames */ + + dq_queue_t bufferq; + snd_pcm_state_t state; + bool stopping; + bool running; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int snd_pcm_ioctl(int fd, int cmd, unsigned long arg) +{ + int ret; + + ret = ioctl(fd, cmd, arg); + if (ret < 0) + { + ret = -errno; + } + + return ret; +} + +#define snd_pcm_ioctl(fd, cmd, arg) \ + snd_pcm_ioctl(fd, cmd, (unsigned long)(arg)) + +static void snd_pcm_deinit(FAR snd_pcm_t *pcm) +{ + if (pcm->fd < 0) + { + return; + } + + if (pcm->mq >= 0) + { + snd_pcm_ioctl(pcm->fd, AUDIOIOC_UNREGISTERMQ, 0); + + mq_close(pcm->mq); + pcm->mq = -1; + + mq_unlink(pcm->mqname); + } + + snd_pcm_ioctl(pcm->fd, AUDIOIOC_RELEASE, 0); + + close(pcm->fd); + free(pcm); +} + +static int snd_pcm_init(FAR snd_pcm_t *pcm) +{ + char path[32]; + int ret; + + struct mq_attr attr = { + .mq_maxmsg = 16, + .mq_msgsize = sizeof(struct audio_msg_s), + }; + + /* open device */ + + snprintf(path, sizeof(path), CONFIG_AUDIOUTILS_ALSA_LIB_DEV_PATH "/%s", + pcm->devname); + pcm->fd = open(path, O_RDWR | O_CLOEXEC); + if (pcm->fd < 0) + { + return -errno; + } + + /* reserve */ + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_RESERVE, 0); + if (ret < 0) + { + goto out; + } + + /* create message queue */ + + snprintf(pcm->mqname, sizeof(pcm->mqname), "/tmp/%p", pcm); + pcm->mq = + mq_open(pcm->mqname, O_RDWR | O_CREAT | O_CLOEXEC, 0644, &attr); + if (pcm->mq < 0) + { + ret = -errno; + goto out; + } + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_REGISTERMQ, pcm->mq); + if (ret < 0) + { + goto out; + } + + pcm->state = SND_PCM_STATE_OPEN; + pcm->volume = 50; + return 0; + +out: + snd_pcm_deinit(pcm); + return ret; +} + +static int snd_pcm_get_bits_per_sample(snd_pcm_format_t format) +{ + switch (format) + { + case SND_PCM_FORMAT_U32: + case SND_PCM_FORMAT_S32: + return 32; + case SND_PCM_FORMAT_U24: + case SND_PCM_FORMAT_S24: + return 24; + case SND_PCM_FORMAT_U16: + case SND_PCM_FORMAT_S16: + return 16; + default: + return 8; + } +} + +static int snd_pcm_poll_available(FAR snd_pcm_t *pcm) +{ + struct audio_buf_desc_s buf_desc; + int now; + int old = dq_count(&pcm->bufferq); + bool nonblock = false; + audinfo("[%s %d]enter.", __func__, __LINE__); + + while (1) + { + FAR struct ap_buffer_s *buffer; + struct audio_msg_s msg; + struct mq_attr stat; + int ret; + + ret = mq_getattr(pcm->mq, &stat); + if (ret < 0) + { + return -errno; + } + + if (nonblock && !stat.mq_curmsgs) + { + break; + } + + ret = mq_receive(pcm->mq, (FAR char *)&msg, sizeof(msg), NULL); + if (ret < 0) + { + return -errno; + } + + if (msg.msg_id == AUDIO_MSG_DEQUEUE) + { + if (pcm->stopping) + { + buf_desc.u.buffer = msg.u.ptr; + snd_pcm_ioctl(pcm->fd, AUDIOIOC_FREEBUFFER, &buf_desc); + } + else + { + buffer = msg.u.ptr; + buffer->curbyte = 0; + dq_addlast(&buffer->dq_entry, &pcm->bufferq); + } + } + else if (msg.msg_id == AUDIO_MSG_COMPLETE) + { + audinfo("[%s][%s] complete\n", __func__, pcm->devname); + pcm->stopping = false; + return 0; + } + + nonblock = true; + } + + now = dq_count(&pcm->bufferq); + if (pcm->periods > 1 && now == pcm->periods && now > old) + { + auderr("[%s %d]audio %s, xrun occurs!\n", __func__, __LINE__, + pcm->devname); + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + { + snd_pcm_pause(pcm, 1); + } + else + { + while (!dq_empty(&pcm->bufferq)) + { + buf_desc.u.buffer = + (FAR struct ap_buffer_s *)dq_remfirst(&pcm->bufferq); + snd_pcm_ioctl(pcm->fd, AUDIOIOC_ENQUEUEBUFFER, &buf_desc); + } + } + + pcm->state = SND_PCM_STATE_XRUN; + + return -EPIPE; + } + + return now; +} + +static int snd_pcm_peek_buffer(FAR snd_pcm_t *pcm, + FAR struct ap_buffer_s **buffer) +{ + int ret; + + *buffer = (FAR struct ap_buffer_s *)dq_peek(&pcm->bufferq); + if (*buffer) + { + return 0; + } + + ret = snd_pcm_poll_available(pcm); + if (ret < 0) + { + return ret; + } + + *buffer = (FAR struct ap_buffer_s *)dq_peek(&pcm->bufferq); + if (!*buffer) + { + return -EAGAIN; + } + + return 0; +} + +#define SCALAR(name, type) \ + static void scalar_##name(FAR uint8_t *dst, FAR const uint8_t *src, \ + int nb_samples, int volume) \ + { \ + FAR type *d = (FAR type *)dst; \ + FAR const type *s = (FAR type *)src; \ + int i = 0; \ + \ + for (i = 0; i < nb_samples; i++) \ + { \ + d[i] = s[i] * (type)volume / 100; \ + } \ + } + +SCALAR(s16, int16_t) +SCALAR(u16, uint16_t) +#ifdef __INT24_DEFINED +SCALAR(s24, int24_t) +SCALAR(u24, uint24_t) +#endif +SCALAR(s32, int32_t) +SCALAR(u32, uint32_t) + +static void snd_pcm_voluem_scalar(FAR snd_pcm_t *pcm, FAR uint8_t *dest, + FAR const uint8_t *src, int len) +{ + switch (pcm->format) + { + case SND_PCM_FORMAT_S16: + scalar_s16(dest, src, len / 2, pcm->volume); + break; + case SND_PCM_FORMAT_U16: + scalar_u16(dest, src, len / 2, pcm->volume); + break; +#ifdef __INT24_DEFINED + case SND_PCM_FORMAT_S24: + scalar_s24(dest, src, len / 3, pcm->volume); + break; + case SND_PCM_FORMAT_U24: + scalar_u24(dest, src, len / 3, pcm->volume); + break; +#endif + case SND_PCM_FORMAT_S32: + scalar_s32(dest, src, len / 4, pcm->volume); + break; + case SND_PCM_FORMAT_U32: + scalar_u32(dest, src, len / 4, pcm->volume); + break; + default: + audinfo("[%s %d]Not support yet! format:%d", __func__, __LINE__, + pcm->format); + assert(0); + } +} + +static int snd_pcm_enqueue_buffer(FAR snd_pcm_t *pcm, + FAR struct ap_buffer_s *buffer) +{ + struct audio_buf_desc_s desc; + audinfo("[%s %d]enter.", __func__, __LINE__); + + if (buffer->curbyte != buffer->nmaxbytes) + { + memset(buffer->samp + buffer->curbyte, 0, + buffer->nmaxbytes - buffer->curbyte); + } + + buffer->nbytes = buffer->curbyte; + buffer->curbyte = 0; + desc.u.buffer = buffer; + return snd_pcm_ioctl(pcm->fd, AUDIOIOC_ENQUEUEBUFFER, &desc); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int snd_pcm_open(FAR snd_pcm_t **pcm, FAR const char *name, + snd_pcm_stream_t stream, int mode) +{ + int ret; + + if (!pcm || !name) + { + return -EINVAL; + } + + if (stream < SND_PCM_STREAM_PLAYBACK || stream > SND_PCM_STREAM_LAST) + { + return -EINVAL; + } + + *pcm = (FAR snd_pcm_t *)malloc(sizeof(snd_pcm_t)); + if (!*pcm) + { + return -ENOMEM; + } + + memset(*pcm, 0, sizeof(snd_pcm_t)); + strlcpy(((*pcm)->devname), name, sizeof((*pcm)->devname)); + (*pcm)->stream = stream; + + ret = snd_pcm_init(*pcm); + + audinfo("[%s %d]doen. ret:%d", __func__, __LINE__, ret); + return ret; +} + +int snd_pcm_prepare(FAR snd_pcm_t *pcm) +{ + struct audio_caps_desc_s caps_desc; + struct audio_buf_desc_s buf_desc; + struct ap_buffer_info_s buf_info; + int bps; + int ret; + int i; + + audinfo("[%s %d]enter.", __func__, __LINE__); + + if (pcm->state == SND_PCM_STATE_XRUN) + { + pcm->state = SND_PCM_STATE_PREPARED; + return 0; + } + + if (pcm->state != SND_PCM_STATE_SETUP) + { + return -EPERM; + } + + bps = snd_pcm_get_bits_per_sample(pcm->format); + pcm->sample_bytes = bps * pcm->channels / 8; + + memset(&caps_desc, 0, sizeof(caps_desc)); + caps_desc.caps.ac_len = sizeof(struct audio_caps_s); + caps_desc.caps.ac_type = pcm->stream == SND_PCM_STREAM_PLAYBACK + ? AUDIO_TYPE_OUTPUT + : AUDIO_TYPE_INPUT; + caps_desc.caps.ac_channels = pcm->channels; + caps_desc.caps.ac_chmap = 0; + caps_desc.caps.ac_controls.hw[0] = pcm->sample_rate; + caps_desc.caps.ac_controls.b[3] = pcm->sample_rate >> 16; + caps_desc.caps.ac_controls.b[2] = bps; + caps_desc.caps.ac_subtype = AUDIO_FMT_PCM; + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_CONFIGURE, &caps_desc); + if (ret < 0) + { + return ret; + } + + audinfo("[%s %d]configure. ch:%d, rate:%d", __func__, __LINE__, + pcm->channels, pcm->sample_rate); + + /* try set recommand params */ + + if (!pcm->periods) + { + pcm->periods = DEFAULT_AUDIO_PERIODS; + } + + if (pcm->period_time) + { + pcm->period_size = pcm->sample_rate / 1000 * pcm->period_time / 1000; + } + + if (!pcm->period_size) + { + pcm->period_time = DEFAULT_AUDIO_PERIOD_TIME; + pcm->period_size = pcm->sample_rate / 1000 * pcm->period_time / 1000; + } + + buf_info.nbuffers = pcm->periods; + buf_info.buffer_size = pcm->period_size * pcm->sample_bytes; + snd_pcm_ioctl(pcm->fd, AUDIOIOC_SETBUFFERINFO, &buf_info); + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_GETBUFFERINFO, &buf_info); + if (ret >= 0) + { + pcm->periods = buf_info.nbuffers; + pcm->period_size = buf_info.buffer_size / pcm->sample_bytes; + } + + pcm->start_threshold = pcm->period_size * pcm->sample_bytes; + + audinfo("[%s %d]set buffer info. n:%d, size:%ld", __func__, __LINE__, + pcm->periods, pcm->period_size); + + dq_init(&pcm->bufferq); + + for (i = 0; i < pcm->periods; i++) + { + FAR struct ap_buffer_s *buffer; + + buf_desc.numbytes = pcm->period_size * pcm->sample_bytes; + buf_desc.u.pbuffer = &buffer; + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_ALLOCBUFFER, &buf_desc); + if (ret < 0) + { + return ret; + } + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + { + dq_addlast(&buffer->dq_entry, &pcm->bufferq); + } + else + { + buffer->nbytes = buffer->nmaxbytes; + buf_desc.u.buffer = buffer; + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_ENQUEUEBUFFER, &buf_desc); + if (ret < 0) + { + return ret; + } + } + } + + pcm->state = SND_PCM_STATE_PREPARED; + + return 0; +} + +int snd_pcm_start(FAR snd_pcm_t *pcm) +{ + int ret; + if (pcm->running) + { + return 0; + } + + if (pcm->state != SND_PCM_STATE_PREPARED) + { + return 0; + } + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_START, 0); + audinfo("[%s %d]start ret:%d\n", __func__, __LINE__, ret); + if (ret < 0) + { + return ret; + } + + pcm->state = SND_PCM_STATE_RUNNING; + pcm->running = true; + return ret; +} + +int snd_pcm_pause(FAR snd_pcm_t *pcm, int enable) +{ + int ret; + if (!pcm->running) + { + return 0; + } + + ret = snd_pcm_ioctl(pcm->fd, enable ? AUDIOIOC_PAUSE : AUDIOIOC_RESUME, 0); + + audinfo("[%s %d]enable:%d, pause ret:%d\n", __func__, __LINE__, enable, + ret); + if (ret >= 0) + { + pcm->state = enable ? SND_PCM_STATE_PAUSED : SND_PCM_STATE_RUNNING; + } + + return ret; +} + +int snd_pcm_close(FAR snd_pcm_t *pcm) +{ + struct audio_buf_desc_s buf_desc; + int dc = dq_count(&pcm->bufferq); + audinfo("[%s %d]enter.\n", __func__, __LINE__); + + if (!pcm->running && pcm->state == SND_PCM_STATE_PREPARED && dc > 0 && + dc < pcm->periods) + { + snd_pcm_ioctl(pcm->fd, AUDIOIOC_START, 0); + pcm->running = true; + } + + if (pcm->running) + { + snd_pcm_ioctl(pcm->fd, AUDIOIOC_STOP, 0); + pcm->running = false; + pcm->stopping = true; + } + + while (!dq_empty(&pcm->bufferq)) + { + buf_desc.u.buffer = + (FAR struct ap_buffer_s *)dq_remfirst(&pcm->bufferq); + snd_pcm_ioctl(pcm->fd, AUDIOIOC_FREEBUFFER, &buf_desc); + } + + while (pcm->stopping) + { + snd_pcm_poll_available(pcm); + } + + pcm->state = SND_PCM_STATE_SUSPENDED; + + snd_pcm_deinit(pcm); + + return 0; +} + +int snd_pcm_delay(FAR snd_pcm_t *pcm, FAR snd_pcm_sframes_t *delayp) +{ + int ret; + *delayp = 0; + + if (pcm->stream != SND_PCM_STREAM_PLAYBACK) + { + return 0; + } + + if (pcm->state != SND_PCM_STATE_RUNNING) + { + return 0; + } + + ret = snd_pcm_ioctl(pcm->fd, AUDIOIOC_GETLATENCY, delayp); + audinfo("[%s %d]get delay:%ld", __func__, __LINE__, *delayp); + + return ret; +} + +int snd_pcm_drop(FAR snd_pcm_t *pcm) +{ + return 0; +} + +int snd_pcm_drain(FAR snd_pcm_t *pcm) +{ + return 0; +} + +int snd_pcm_resume(FAR snd_pcm_t *pcm) +{ + if (pcm->state == SND_PCM_STATE_XRUN) + { + pcm->state = SND_PCM_STATE_PREPARED; + } + + return 0; +} + +int snd_pcm_recover(FAR snd_pcm_t *pcm, int err, int silent) +{ + if (pcm->state == SND_PCM_STATE_XRUN) + { + pcm->state = SND_PCM_STATE_PREPARED; + } + + return 0; +} + +int snd_pcm_wait(FAR snd_pcm_t *pcm, int timeout) +{ + audinfo("[%s %d]enter. wait:%dms", __func__, __LINE__, timeout); + usleep(timeout * 1000); + return 0; +} + +snd_pcm_sframes_t snd_pcm_writei(FAR snd_pcm_t *pcm, FAR const void *buffer, + snd_pcm_uframes_t size) +{ + int left = snd_pcm_frames_to_bytes(pcm, size); + FAR struct ap_buffer_s *apb; + FAR const uint8_t *data = (FAR uint8_t *)buffer; + int ret = 0; + audinfo("[%s %d]enter. size:%ld", __func__, __LINE__, size); + + while (left > 0 && !pcm->stopping) + { + int len; + + ret = snd_pcm_peek_buffer(pcm, &apb); + if (ret == -EPIPE) + { + return ret; + } + else if (ret == -EAGAIN) + { + continue; + } + else if (ret < 0) + { + break; + } + + len = FFMIN(apb->nmaxbytes - apb->curbyte, left); + snd_pcm_voluem_scalar(pcm, (apb->samp + apb->curbyte), data, len); + apb->curbyte += len; + + if (apb->curbyte == apb->nmaxbytes) + { + dq_remfirst(&pcm->bufferq); + + ret = snd_pcm_enqueue_buffer(pcm, apb); + if (ret < 0) + { + break; + } + + if (pcm->state == SND_PCM_STATE_PREPARED && + ((pcm->periods - dq_count(&pcm->bufferq)) * + pcm->period_size >= + pcm->start_threshold)) + { + if (pcm->running) + { + ret = snd_pcm_pause(pcm, 0); + } + else + { + ret = snd_pcm_start(pcm); + } + + if (ret < 0) + { + break; + } + } + } + + data += len; + left -= len; + } + + return size - snd_pcm_bytes_to_frames(pcm, left); +} + +int snd_pcm_set_volume(FAR snd_pcm_t *pcm, int volume) +{ + if (volume < 0 || volume > 100) + { + return -EINVAL; + } + + audinfo("[%s %d]set volume:%d", __func__, __LINE__, volume); + pcm->volume = volume; + + return 0; +} + +int snd_pcm_set_params(FAR snd_pcm_t *pcm, snd_pcm_format_t format, + snd_pcm_access_t access, unsigned int channels, + unsigned int rate, int soft_resample, + unsigned int latency) +{ + audinfo("[%s %d]format:%d, ch:%d, rate:%d", __func__, __LINE__, format, + channels, rate); + assert(pcm); + + pcm->format = format; + pcm->channels = channels; + pcm->sample_rate = rate; + + pcm->state = SND_PCM_STATE_SETUP; + + return 0; +} + +int snd_pcm_get_params(FAR snd_pcm_t *pcm, + FAR snd_pcm_uframes_t *buffer_size, + FAR snd_pcm_uframes_t *period_size) +{ + assert(pcm); + + *period_size = pcm->period_size; + *buffer_size = pcm->period_size * pcm->periods; + + return 0; +} + +snd_pcm_sframes_t snd_pcm_bytes_to_frames(FAR snd_pcm_t *pcm, ssize_t bytes) +{ + assert(pcm); + return bytes / pcm->sample_bytes; +} + +ssize_t snd_pcm_frames_to_bytes(FAR snd_pcm_t *pcm, snd_pcm_sframes_t frames) +{ + assert(pcm); + return frames * pcm->sample_bytes; +} + +#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v + +FAR static const char *const snd_pcm_format_names[] = +{ + FORMAT(S8), + FORMAT(U8), + FORMAT(S16_LE), + FORMAT(S16_BE), + FORMAT(U16_LE), + FORMAT(U16_BE), + FORMAT(S24_LE), + FORMAT(S24_BE), + FORMAT(U24_LE), + FORMAT(U24_BE), + FORMAT(S32_LE), + FORMAT(S32_BE), + FORMAT(U32_LE), + FORMAT(U32_BE), +}; + +FAR const char *snd_pcm_format_name(snd_pcm_format_t format) +{ + if (format > SND_PCM_FORMAT_LAST) + { + return NULL; + } + + return snd_pcm_format_names[format]; +} + +/**************************************************************************** + * Hw Functions + ****************************************************************************/ + +static inline int hw_is_mask(int var) +{ + return var >= SND_PCM_HW_PARAM_FIRST_MASK && + var <= SND_PCM_HW_PARAM_LAST_MASK; +} + +static inline int hw_is_range(int var) +{ + return var >= SND_PCM_HW_PARAM_FIRST_RANGE && + var <= SND_PCM_HW_PARAM_LAST_RANGE; +} + +static int _snd_pcm_hw_param_set(FAR snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, unsigned int val) +{ + FAR union snd_interval *interval = NULL; + + assert(params); + interval = ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; + if (hw_is_mask(var)) + { + interval->mask = (1 << val); + } + else + { + interval->range.min = val; + } + + return 0; +} + +static int _snd_pcm_hw_param_get(FAR const snd_pcm_hw_params_t *params, + snd_pcm_hw_param_t var, + FAR unsigned int *val) +{ + FAR const union snd_interval *interval; + + assert(params); + interval = ¶ms->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL]; + if (hw_is_mask(var)) + { + *val = (interval->mask >> 1); + } + else + { + *val = interval->range.min; + } + + return 0; +} + +#define _snd_pcm_hw_param_set(params, var, val) \ + _snd_pcm_hw_param_set(params, var, (unsigned int)(val)) +#define _snd_pcm_hw_param_get(params, var, val) \ + _snd_pcm_hw_param_get(params, var, (FAR unsigned int *)(val)) + +static int _snd_pcm_hw_params_internal(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params) +{ + int period_size; + int buffer_size; + + assert(pcm && params); + + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_FORMAT, &pcm->format); + if (!pcm->format) + { + pcm->format = SND_PCM_FORMAT_S16; + } + + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, &pcm->channels); + if (!pcm->channels) + { + pcm->channels = 2; + } + + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_RATE, &pcm->sample_rate); + if (!pcm->sample_rate) + { + pcm->sample_rate = 44100; + } + + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIODS, &pcm->periods); + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &pcm->period_time); + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &period_size); + _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + &buffer_size); + if (period_size && buffer_size) + { + pcm->periods = buffer_size / period_size; + pcm->period_time = period_size * 1000 * 1000 / pcm->sample_rate; + } + + audinfo("[%s %d]format:%d, ch:%d, rate:%d, periods:%d, period_time:%d", + __func__, __LINE__, pcm->format, pcm->channels, pcm->sample_rate, + pcm->periods, pcm->period_time); + + pcm->state = SND_PCM_STATE_SETUP; + + return 0; +} + +int snd_pcm_hw_params_any(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params) +{ + return 0; +} + +int snd_pcm_hw_params_set_format(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_format_t format) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT, format); +} + +int snd_pcm_hw_params_set_channels(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, val); +} + +int snd_pcm_hw_params_get_channels(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_CHANNELS, val); +} + +int snd_pcm_hw_params_set_rate(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val, int dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE, val); +} + +int snd_pcm_hw_params_set_rate_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE, *val); +} + +int snd_pcm_hw_params_get_rate(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_RATE, val); +} + +int snd_pcm_hw_params_set_period_time(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int us, int dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME, us); +} + +int snd_pcm_hw_params_set_period_time_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *us, + FAR int *dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME, *us); +} + +int snd_pcm_hw_params_get_period_time(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *us, FAR int *dir) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_TIME, us); +} + +int snd_pcm_hw_params_set_period_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_uframes_t val, int dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_SIZE, val); +} + +int snd_pcm_hw_params_set_period_size_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val, + FAR int *dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_SIZE, *val); +} + +int snd_pcm_hw_params_get_period_size(FAR const snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val, + FAR int *dir) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIOD_SIZE, val); +} + +int snd_pcm_hw_params_set_periods(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val, int dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIODS, val); +} + +int snd_pcm_hw_params_set_periods_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIODS, *val); +} + +int snd_pcm_hw_params_get_periods(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_PERIODS, val); +} + +int snd_pcm_hw_params_set_buffer_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_uframes_t val) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE, val); +} + +int snd_pcm_hw_params_set_buffer_size_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE, *val); +} + +int snd_pcm_hw_params_get_buffer_size(FAR const snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_SIZE, val); +} + +int snd_pcm_hw_params_set_buffer_time(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int us) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME, us); +} + +int snd_pcm_hw_params_set_buffer_time_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *us, + FAR int *dir) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME, *us); +} + +int snd_pcm_hw_params_get_buffer_time(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *us, FAR int *dir) +{ + return _snd_pcm_hw_param_get(params, SND_PCM_HW_PARAM_BUFFER_TIME, us); +} + +int snd_pcm_hw_params_set_access(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_access_t access) +{ + return _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_ACCESS, access); +} + +int snd_pcm_hw_params(FAR snd_pcm_t *pcm, FAR snd_pcm_hw_params_t *params) +{ + int err; + assert(pcm && params); + err = _snd_pcm_hw_params_internal(pcm, params); + if (err < 0) + { + return err; + } + + err = snd_pcm_prepare(pcm); + return err; +} + +/**************************************************************************** + * Sw Functions + ****************************************************************************/ + +int snd_pcm_sw_params_current(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params) +{ + assert(pcm && params); + + memset(params, 0, sizeof(snd_pcm_sw_params_t)); + params->start_threshold = pcm->start_threshold; + + return 0; +} + +int snd_pcm_sw_params_set_start_threshold(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val) +{ + assert(pcm && params); + + params->start_threshold = val; + return 0; +} + +int snd_pcm_sw_params_get_start_threshold(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + assert(params); + + *val = params->start_threshold; + return 0; +} + +int snd_pcm_sw_params_set_stop_threshold(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val) +{ + assert(pcm && params); + + params->stop_threshold = val; + return 0; +} + +int snd_pcm_sw_params_get_stop_threshold(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + assert(params); + + *val = params->stop_threshold; + return 0; +} + +int snd_pcm_sw_params_set_silence_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val) +{ + assert(pcm && params); + + params->silence_size = val; + return 0; +} + +int snd_pcm_sw_params_get_silence_size(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + assert(params); + + *val = params->silence_size; + return 0; +} + +int snd_pcm_sw_params_set_avail_min(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val) +{ + assert(pcm && params); + + params->avail_min = val; + return 0; +} + +int snd_pcm_sw_params_get_avail_min(FAR const snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + assert(params); + + *val = params->avail_min; + return 0; +} + +int snd_pcm_sw_params_get_boundary(FAR const snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val) +{ + assert(params); + + *val = params->boundary; + return 0; +} + +int snd_pcm_sw_params(FAR snd_pcm_t *pcm, FAR snd_pcm_sw_params_t *params) +{ + assert(pcm && params); + + pcm->start_threshold = params->start_threshold; + return 0; +} diff --git a/audioutils/alsa-lib/include/alsa_error.h b/audioutils/alsa-lib/include/alsa_error.h new file mode 100644 index 0000000000..ccf92f6da1 --- /dev/null +++ b/audioutils/alsa-lib/include/alsa_error.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * apps/audioutils/alsa-lib/include/alsa_error.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +#ifndef __ALSA_ERROR_H +#define __ALSA_ERROR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +FAR const char *snd_strerror(int errnum); + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_ERROR_H */ \ No newline at end of file diff --git a/audioutils/alsa-lib/include/alsa_pcm.h b/audioutils/alsa-lib/include/alsa_pcm.h new file mode 100644 index 0000000000..c2749489b4 --- /dev/null +++ b/audioutils/alsa-lib/include/alsa_pcm.h @@ -0,0 +1,444 @@ +/**************************************************************************** + * apps/audioutils/alsa-lib/include/alsa_pcm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +#ifndef __ALSA_PCM_H +#define __ALSA_PCM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Pre-processor Prototypes + ****************************************************************************/ + +#define SND_PCM_HW_PARAM_ACCESS 0 +#define SND_PCM_HW_PARAM_FORMAT 1 +#define SND_PCM_HW_PARAM_FIRST_MASK SND_PCM_HW_PARAM_ACCESS +#define SND_PCM_HW_PARAM_LAST_MASK SND_PCM_HW_PARAM_FORMAT +#define SND_PCM_HW_PARAM_SAMPLE_BITS 2 +#define SND_PCM_HW_PARAM_FRAME_BITS 3 +#define SND_PCM_HW_PARAM_CHANNELS 4 +#define SND_PCM_HW_PARAM_RATE 5 +#define SND_PCM_HW_PARAM_PERIOD_TIME 6 +#define SND_PCM_HW_PARAM_PERIOD_SIZE 7 +#define SND_PCM_HW_PARAM_PERIOD_BYTES 8 +#define SND_PCM_HW_PARAM_PERIODS 9 +#define SND_PCM_HW_PARAM_BUFFER_TIME 10 +#define SND_PCM_HW_PARAM_BUFFER_SIZE 11 +#define SND_PCM_HW_PARAM_BUFFER_BYTES 12 +#define SND_PCM_HW_PARAM_FIRST_RANGE SND_PCM_HW_PARAM_SAMPLE_BITS +#define SND_PCM_HW_PARAM_LAST_RANGE SND_PCM_HW_PARAM_BUFFER_BYTES +#define SND_PCM_HW_PARAM_FIRST_INTERVAL SND_PCM_HW_PARAM_ACCESS +#define SND_PCM_HW_PARAM_LAST_INTERVAL SND_PCM_HW_PARAM_BUFFER_BYTES + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Unsigned frames quantity */ + +typedef unsigned long snd_pcm_uframes_t; + +/* Signed frames quantity */ + +typedef long snd_pcm_sframes_t; + +typedef int snd_pcm_hw_param_t; + +/* PCM handle */ + +typedef struct _snd_pcm snd_pcm_t; + +/* PCM stream (direction) */ + +typedef enum _snd_pcm_stream +{ + /* Playback stream */ + + SND_PCM_STREAM_PLAYBACK = 0, + + /* Capture stream */ + + SND_PCM_STREAM_CAPTURE, + SND_PCM_STREAM_LAST = SND_PCM_STREAM_CAPTURE +} snd_pcm_stream_t; + +/* PCM access type */ + +typedef enum _snd_pcm_access +{ + /* mmap access with simple interleaved channels */ + + SND_PCM_ACCESS_MMAP_INTERLEAVED = 0, + + /* mmap access with simple non interleaved channels */ + + SND_PCM_ACCESS_MMAP_NONINTERLEAVED, + + /* mmap access with complex placement */ + + SND_PCM_ACCESS_MMAP_COMPLEX, + + /* snd_pcm_readi/snd_pcm_writei access */ + + SND_PCM_ACCESS_RW_INTERLEAVED, + + /* snd_pcm_readn/snd_pcm_writen access */ + + SND_PCM_ACCESS_RW_NONINTERLEAVED, + SND_PCM_ACCESS_LAST = SND_PCM_ACCESS_RW_NONINTERLEAVED +} snd_pcm_access_t; + +/* PCM sample format */ + +typedef enum _snd_pcm_format +{ + /* Unknown */ + + SND_PCM_FORMAT_UNKNOWN = -1, + + /* Signed 8 bit */ + + SND_PCM_FORMAT_S8 = 0, + + /* Unsigned 8 bit */ + + SND_PCM_FORMAT_U8, + + /* Signed 16 bit Little Endian */ + + SND_PCM_FORMAT_S16_LE, + + /* Signed 16 bit Big Endian */ + + SND_PCM_FORMAT_S16_BE, + + /* Unsigned 16 bit Little Endian */ + + SND_PCM_FORMAT_U16_LE, + + /* Unsigned 16 bit Big Endian */ + + SND_PCM_FORMAT_U16_BE, + + /* Signed 24 bit Little Endian using low three bytes in 32-bit word */ + + SND_PCM_FORMAT_S24_LE, + + /* Signed 24 bit Big Endian using low three bytes in 32-bit word */ + + SND_PCM_FORMAT_S24_BE, + + /* Unsigned 24 bit Little Endian using low three bytes in 32-bit word */ + + SND_PCM_FORMAT_U24_LE, + + /* Unsigned 24 bit Big Endian using low three bytes in 32-bit word */ + + SND_PCM_FORMAT_U24_BE, + + /* Signed 32 bit Little Endian */ + + SND_PCM_FORMAT_S32_LE, + + /* Signed 32 bit Big Endian */ + + SND_PCM_FORMAT_S32_BE, + + /* Unsigned 32 bit Little Endian */ + + SND_PCM_FORMAT_U32_LE, + + /* Unsigned 32 bit Big Endian */ + + SND_PCM_FORMAT_U32_BE, + + /* only support little endian Signed 16 bit CPU endian */ + + SND_PCM_FORMAT_S16 = SND_PCM_FORMAT_S16_LE, + + /* Unsigned 16 bit CPU endian */ + + SND_PCM_FORMAT_U16 = SND_PCM_FORMAT_U16_LE, + + /* Signed 24 bit CPU endian */ + + SND_PCM_FORMAT_S24 = SND_PCM_FORMAT_S24_LE, + + /* Unsigned 24 bit CPU endian */ + + SND_PCM_FORMAT_U24 = SND_PCM_FORMAT_U24_LE, + + /* Signed 32 bit CPU endian */ + + SND_PCM_FORMAT_S32 = SND_PCM_FORMAT_S32_LE, + + /* Unsigned 32 bit CPU endian */ + + SND_PCM_FORMAT_U32 = SND_PCM_FORMAT_U32_LE, + + SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_U32_BE, +} snd_pcm_format_t; + +/* PCM state */ + +typedef enum _snd_pcm_state +{ + /* Open */ + + SND_PCM_STATE_OPEN = 0, + + /* Setup installed */ + + SND_PCM_STATE_SETUP, + + /* Ready to start */ + + SND_PCM_STATE_PREPARED, + + /* Running */ + + SND_PCM_STATE_RUNNING, + + /* Stopped: underrun (playback) or overrun (capture) detected */ + + SND_PCM_STATE_XRUN, + + /* Draining: running (playback) or stopped (capture) */ + + SND_PCM_STATE_DRAINING, + + /* Paused */ + + SND_PCM_STATE_PAUSED, + + /* Hardware is suspended */ + + SND_PCM_STATE_SUSPENDED, + + /* Hardware is disconnected */ + + SND_PCM_STATE_DISCONNECTED, + SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED, + + /* Private - used internally in the library - do not use */ + + SND_PCM_STATE_PRIVATE1 = 1024 +} snd_pcm_state_t; + +union snd_interval +{ + struct + { + uint32_t min; + uint32_t max; + int openmin; /* whether the interval is left-open */ + int openmax; /* whether the interval is right-open */ + int integer; /* whether the value is integer or not */ + int empty; + } range; + uint32_t mask; +}; + +typedef struct snd_pcm_hw_params +{ + union snd_interval intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - + SND_PCM_HW_PARAM_FIRST_INTERVAL + 1]; +} snd_pcm_hw_params_t; + +typedef struct snd_pcm_sw_params +{ + snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */ + snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */ + snd_pcm_uframes_t silence_size; /* silence block size */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ +} snd_pcm_sw_params_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int snd_pcm_open(FAR snd_pcm_t **pcm, FAR const char *name, + snd_pcm_stream_t stream, int mode); +int snd_pcm_close(FAR snd_pcm_t *pcm); +int snd_pcm_prepare(FAR snd_pcm_t *pcm); +int snd_pcm_start(FAR snd_pcm_t *pcm); +int snd_pcm_pause(FAR snd_pcm_t *pcm, int enable); +int snd_pcm_delay(FAR snd_pcm_t *pcm, FAR snd_pcm_sframes_t *delayp); +int snd_pcm_drop(FAR snd_pcm_t *pcm); +int snd_pcm_drain(FAR snd_pcm_t *pcm); +int snd_pcm_resume(FAR snd_pcm_t *pcm); +int snd_pcm_recover(FAR snd_pcm_t *pcm, int err, int silent); +int snd_pcm_wait(FAR snd_pcm_t *pcm, int timeout); + +snd_pcm_sframes_t snd_pcm_writei(FAR snd_pcm_t *pcm, FAR const void *buffer, + snd_pcm_uframes_t size); + +int snd_pcm_set_volume(FAR snd_pcm_t *pcm, int volume); +int snd_pcm_set_params(FAR snd_pcm_t *pcm, snd_pcm_format_t format, + snd_pcm_access_t access, unsigned int channels, + unsigned int rate, int soft_resample, + unsigned int latency); +int snd_pcm_get_params(FAR snd_pcm_t *pcm, + FAR snd_pcm_uframes_t *buffer_size, + FAR snd_pcm_uframes_t *period_size); + +snd_pcm_sframes_t snd_pcm_bytes_to_frames(FAR snd_pcm_t *pcm, ssize_t bytes); +ssize_t snd_pcm_frames_to_bytes(FAR snd_pcm_t *pcm, + snd_pcm_sframes_t frames); + +FAR const char *snd_pcm_format_name(const snd_pcm_format_t format); + +/* hw & sw define */ + +#define __snd_alloca(ptr, type) \ + do { \ + *ptr = (FAR type*)alloca(sizeof(type)); \ + memset(*ptr, 0, sizeof(type)); \ + } while (0) + +#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params_t) + +int snd_pcm_hw_params_any(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params); + +int snd_pcm_hw_params_set_format(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_format_t format); + +int snd_pcm_hw_params_set_channels(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val); +int snd_pcm_hw_params_get_channels(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val); + +int snd_pcm_hw_params_set_rate(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val, int dir); +int snd_pcm_hw_params_set_rate_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir); +int snd_pcm_hw_params_get_rate(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir); + +int snd_pcm_hw_params_set_period_time(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int us, int dir); +int snd_pcm_hw_params_set_period_time_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *us, + FAR int *dir); +int snd_pcm_hw_params_get_period_time(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *us, FAR int *dir); + +int snd_pcm_hw_params_set_period_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_uframes_t val, int dir); +int snd_pcm_hw_params_set_period_size_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val, + FAR int *dir); +int snd_pcm_hw_params_get_period_size(FAR const snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val, + FAR int *dir); + +int snd_pcm_hw_params_set_periods(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int val, int dir); +int snd_pcm_hw_params_set_periods_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir); +int snd_pcm_hw_params_get_periods(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *val, FAR int *dir); + +int snd_pcm_hw_params_set_buffer_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_uframes_t val); +int snd_pcm_hw_params_set_buffer_size_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val); +int snd_pcm_hw_params_get_buffer_size(FAR const snd_pcm_hw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_hw_params_set_buffer_time(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + unsigned int us); +int snd_pcm_hw_params_set_buffer_time_near(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + FAR unsigned int *us, + FAR int *dir); +int snd_pcm_hw_params_get_buffer_time(FAR const snd_pcm_hw_params_t *params, + FAR unsigned int *us, FAR int *dir); + +int snd_pcm_hw_params_set_access(FAR snd_pcm_t *pcm, + FAR snd_pcm_hw_params_t *params, + snd_pcm_access_t access); + +int snd_pcm_hw_params(FAR snd_pcm_t *pcm, FAR snd_pcm_hw_params_t *params); + +#define snd_pcm_sw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_sw_params_t) + +int snd_pcm_sw_params_current(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params); + +int snd_pcm_sw_params_set_start_threshold(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_start_threshold(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_sw_params_set_stop_threshold(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_stop_threshold(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_sw_params_set_silence_size(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_silence_size(FAR snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_sw_params_set_avail_min(FAR snd_pcm_t *pcm, + FAR snd_pcm_sw_params_t *params, + snd_pcm_uframes_t val); +int snd_pcm_sw_params_get_avail_min(FAR const snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_sw_params_get_boundary(FAR const snd_pcm_sw_params_t *params, + FAR snd_pcm_uframes_t *val); + +int snd_pcm_sw_params(FAR snd_pcm_t *pcm, FAR snd_pcm_sw_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_PCM_H */ diff --git a/audioutils/alsa-lib/include/asoundlib.h b/audioutils/alsa-lib/include/asoundlib.h new file mode 100644 index 0000000000..780e1237af --- /dev/null +++ b/audioutils/alsa-lib/include/asoundlib.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * apps/audioutils/alsa-lib/include/asoundlib.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +#ifndef __ASOUNDLIB_H +#define __ASOUNDLIB_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#endif /* __ASOUNDLIB_H */