diff options
Diffstat (limited to 'libaudio/alsa_pcm.c')
-rw-r--r-- | libaudio/alsa_pcm.c | 405 |
1 files changed, 0 insertions, 405 deletions
diff --git a/libaudio/alsa_pcm.c b/libaudio/alsa_pcm.c deleted file mode 100644 index 5673391..0000000 --- a/libaudio/alsa_pcm.c +++ /dev/null @@ -1,405 +0,0 @@ -/* -** Copyright 2010, The Android Open-Source Project -** -** Licensed 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. -*/ - -#define LOG_TAG "alsa_pcm" -//#define LOG_NDEBUG 0 -#include <cutils/log.h> -#include <cutils/config_utils.h> - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> - -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/time.h> - -#include <linux/ioctl.h> - -#include "alsa_audio.h" - -#define __force -#define __bitwise -#define __user -#include "asound.h" - -#define DEBUG 0 - -/* alsa parameter manipulation cruft */ - -#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL - -static inline int param_is_mask(int p) -{ - return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && - (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); -} - -static inline int param_is_interval(int p) -{ - return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) && - (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL); -} - -static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n) -{ - return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]); -} - -static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) -{ - return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); -} - -static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) -{ - if (bit >= SNDRV_MASK_MAX) - return; - if (param_is_mask(n)) { - struct snd_mask *m = param_to_mask(p, n); - m->bits[0] = 0; - m->bits[1] = 0; - m->bits[bit >> 5] |= (1 << (bit & 31)); - } -} - -static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned val) -{ - if (param_is_interval(n)) { - struct snd_interval *i = param_to_interval(p, n); - i->min = val; - } -} - -static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned val) -{ - if (param_is_interval(n)) { - struct snd_interval *i = param_to_interval(p, n); - i->max = val; - } -} - -static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned val) -{ - if (param_is_interval(n)) { - struct snd_interval *i = param_to_interval(p, n); - i->min = val; - i->max = val; - i->integer = 1; - } -} - -static void param_init(struct snd_pcm_hw_params *p) -{ - int n; - memset(p, 0, sizeof(*p)); - for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; - n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { - struct snd_mask *m = param_to_mask(p, n); - m->bits[0] = ~0; - m->bits[1] = ~0; - } - for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; - n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { - struct snd_interval *i = param_to_interval(p, n); - i->min = 0; - i->max = ~0; - } -} - -/* debugging gunk */ - -#if DEBUG -static const char *param_name[PARAM_MAX+1] = { - [SNDRV_PCM_HW_PARAM_ACCESS] = "access", - [SNDRV_PCM_HW_PARAM_FORMAT] = "format", - [SNDRV_PCM_HW_PARAM_SUBFORMAT] = "subformat", - - [SNDRV_PCM_HW_PARAM_SAMPLE_BITS] = "sample_bits", - [SNDRV_PCM_HW_PARAM_FRAME_BITS] = "frame_bits", - [SNDRV_PCM_HW_PARAM_CHANNELS] = "channels", - [SNDRV_PCM_HW_PARAM_RATE] = "rate", - [SNDRV_PCM_HW_PARAM_PERIOD_TIME] = "period_time", - [SNDRV_PCM_HW_PARAM_PERIOD_SIZE] = "period_size", - [SNDRV_PCM_HW_PARAM_PERIOD_BYTES] = "period_bytes", - [SNDRV_PCM_HW_PARAM_PERIODS] = "periods", - [SNDRV_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time", - [SNDRV_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size", - [SNDRV_PCM_HW_PARAM_BUFFER_BYTES] = "buffer_bytes", - [SNDRV_PCM_HW_PARAM_TICK_TIME] = "tick_time", -}; - -static void param_dump(struct snd_pcm_hw_params *p) -{ - int n; - - for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; - n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { - struct snd_mask *m = param_to_mask(p, n); - LOGV("%s = %08x%08x\n", param_name[n], - m->bits[1], m->bits[0]); - } - for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; - n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { - struct snd_interval *i = param_to_interval(p, n); - LOGV("%s = (%d,%d) omin=%d omax=%d int=%d empty=%d\n", - param_name[n], i->min, i->max, i->openmin, - i->openmax, i->integer, i->empty); - } - LOGV("info = %08x\n", p->info); - LOGV("msbits = %d\n", p->msbits); - LOGV("rate = %d/%d\n", p->rate_num, p->rate_den); - LOGV("fifo = %d\n", (int) p->fifo_size); -} - -static void info_dump(struct snd_pcm_info *info) -{ - LOGV("device = %d\n", info->device); - LOGV("subdevice = %d\n", info->subdevice); - LOGV("stream = %d\n", info->stream); - LOGV("card = %d\n", info->card); - LOGV("id = '%s'\n", info->id); - LOGV("name = '%s'\n", info->name); - LOGV("subname = '%s'\n", info->subname); - LOGV("dev_class = %d\n", info->dev_class); - LOGV("dev_subclass = %d\n", info->dev_subclass); - LOGV("subdevices_count = %d\n", info->subdevices_count); - LOGV("subdevices_avail = %d\n", info->subdevices_avail); -} -#else -static void param_dump(struct snd_pcm_hw_params *p) {} -static void info_dump(struct snd_pcm_info *info) {} -#endif - -#define PCM_ERROR_MAX 128 - -struct pcm { - int fd; - unsigned flags; - int running:1; - int underruns; - unsigned buffer_size; - char error[PCM_ERROR_MAX]; -}; - -unsigned pcm_buffer_size(struct pcm *pcm) -{ - return pcm->buffer_size; -} - -const char* pcm_error(struct pcm *pcm) -{ - return pcm->error; -} - -static int oops(struct pcm *pcm, int e, const char *fmt, ...) -{ - va_list ap; - int sz; - - va_start(ap, fmt); - vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); - va_end(ap); - sz = strlen(pcm->error); - - if (errno) - snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, - ": %s", strerror(e)); - return -1; -} - -int pcm_write(struct pcm *pcm, void *data, unsigned count) -{ - struct snd_xferi x; - - if (pcm->flags & PCM_IN) - return -EINVAL; - - x.buf = data; - x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4); - - for (;;) { - if (!pcm->running) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) - return oops(pcm, errno, "cannot prepare channel"); - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) - return oops(pcm, errno, "cannot write initial data"); - pcm->running = 1; - return 0; - } - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { - pcm->running = 0; - if (errno == EPIPE) { - /* we failed to make our window -- try to restart */ - pcm->underruns++; - continue; - } - return oops(pcm, errno, "cannot write stream data"); - } - return 0; - } -} - -int pcm_read(struct pcm *pcm, void *data, unsigned count) -{ - struct snd_xferi x; - - if (!(pcm->flags & PCM_IN)) - return -EINVAL; - - x.buf = data; - x.frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4); - -// LOGV("read() %d frames", x.frames); - for (;;) { - if (!pcm->running) { - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) - return oops(pcm, errno, "cannot prepare channel"); - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) - return oops(pcm, errno, "cannot start channel"); - pcm->running = 1; - } - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { - pcm->running = 0; - if (errno == EPIPE) { - /* we failed to make our window -- try to restart */ - pcm->underruns++; - continue; - } - return oops(pcm, errno, "cannot read stream data"); - } -// LOGV("read() got %d frames", x.frames); - return 0; - } -} - -static struct pcm bad_pcm = { - .fd = -1, -}; - -int pcm_close(struct pcm *pcm) -{ - if (pcm == &bad_pcm) - return 0; - - if (pcm->fd >= 0) - close(pcm->fd); - pcm->running = 0; - pcm->buffer_size = 0; - pcm->fd = -1; - return 0; -} - -struct pcm *pcm_open(unsigned flags) -{ - const char *dname; - struct pcm *pcm; - struct snd_pcm_info info; - struct snd_pcm_hw_params params; - struct snd_pcm_sw_params sparams; - unsigned period_sz; - unsigned period_cnt; - - LOGV("pcm_open(0x%08x)",flags); - - pcm = calloc(1, sizeof(struct pcm)); - if (!pcm) - return &bad_pcm; - - if (flags & PCM_IN) { - dname = "/dev/snd/pcmC0D0c"; - } else { - dname = "/dev/snd/pcmC0D0p"; - } - - LOGV("pcm_open() period sz multiplier %d", - ((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1); - period_sz = 128 * (((flags & PCM_PERIOD_SZ_MASK) >> PCM_PERIOD_SZ_SHIFT) + 1); - LOGV("pcm_open() period cnt %d", - ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN); - period_cnt = ((flags & PCM_PERIOD_CNT_MASK) >> PCM_PERIOD_CNT_SHIFT) + PCM_PERIOD_CNT_MIN; - - pcm->flags = flags; - pcm->fd = open(dname, O_RDWR); - if (pcm->fd < 0) { - oops(pcm, errno, "cannot open device '%s'"); - return pcm; - } - - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { - oops(pcm, errno, "cannot get info - %s"); - goto fail; - } - info_dump(&info); - - LOGV("pcm_open() period_cnt %d period_sz %d channels %d", - period_cnt, period_sz, (flags & PCM_MONO) ? 1 : 2); - - param_init(¶ms); - param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, - SNDRV_PCM_ACCESS_RW_INTERLEAVED); - param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_FORMAT_S16_LE); - param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, - SNDRV_PCM_SUBFORMAT_STD); - param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, period_sz); - param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16); - param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, - (flags & PCM_MONO) ? 16 : 32); - param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, - (flags & PCM_MONO) ? 1 : 2); - param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, period_cnt); - param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, 44100); - - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { - oops(pcm, errno, "cannot set hw params"); - goto fail; - } - param_dump(¶ms); - - memset(&sparams, 0, sizeof(sparams)); - sparams.tstamp_mode = SNDRV_PCM_TSTAMP_NONE; - sparams.period_step = 1; - sparams.avail_min = 1; - sparams.start_threshold = period_cnt * period_sz; - sparams.stop_threshold = period_cnt * period_sz; - sparams.xfer_align = period_sz / 2; /* needed for old kernels */ - sparams.silence_size = 0; - sparams.silence_threshold = 0; - - if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { - oops(pcm, errno, "cannot set sw params"); - goto fail; - } - - pcm->buffer_size = period_cnt * period_sz; - pcm->underruns = 0; - return pcm; - -fail: - close(pcm->fd); - pcm->fd = -1; - return pcm; -} - -int pcm_ready(struct pcm *pcm) -{ - return pcm->fd >= 0; -} |