/* pcm.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <limits.h>
//#include <cutils/log.h>
#include <linux/ioctl.h>
#define __force
#define __bitwise
#define __user
#include <sound/asound.h>
#include <tinyalsa/asoundlib.h>
#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL
/* Logs information into a string; follows snprintf() in that
* offset may be greater than size, and though no characters are copied
* into string, characters are still counted into offset. */
#define STRLOG(string, offset, size, ...) \
do { int temp, clipoffset = offset > size ? size : offset; \
temp = snprintf(string + clipoffset, size - clipoffset, __VA_ARGS__); \
if (temp > 0) offset += temp; } while (0)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
#define LOG_TAG "TINY-ALSA"
#define ALOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
#define ALOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)
/* refer to SNDRV_PCM_ACCESS_##index in sound/asound.h. */
static const char * const access_lookup[] = {
"MMAP_INTERLEAVED",
"MMAP_NONINTERLEAVED",
"MMAP_COMPLEX",
"RW_INTERLEAVED",
"RW_NONINTERLEAVED",
};
/* refer to SNDRV_PCM_FORMAT_##index in sound/asound.h. */
static const char * const format_lookup[] = {
/*[0] =*/ "S8",
"U8",
"S16_LE",
"S16_BE",
"U16_LE",
"U16_BE",
"S24_LE",
"S24_BE",
"U24_LE",
"U24_BE",
"S32_LE",
"S32_BE",
"U32_LE",
"U32_BE",
"FLOAT_LE",
"FLOAT_BE",
"FLOAT64_LE",
"FLOAT64_BE",
"IEC958_SUBFRAME_LE",
"IEC958_SUBFRAME_BE",
"MU_LAW",
"A_LAW",
"IMA_ADPCM",
"MPEG",
/*[24] =*/ "GSM",
/* gap */
[31] = "SPECIAL",
"S24_3LE",
"S24_3BE",
"U24_3LE",
"U24_3BE",
"S20_3LE",
"S20_3BE",
"U20_3LE",
"U20_3BE",
"S18_3LE",
"S18_3BE",
"U18_3LE",
/*[43] =*/ "U18_3BE",
#if 0
/* recent additions, may not be present on local asound.h */
"G723_24",
"G723_24_1B",
"G723_40",
"G723_40_1B",
"DSD_U8",
"DSD_U16_LE",
#endif
};
/* refer to SNDRV_PCM_SUBFORMAT_##index in sound/asound.h. */
static const char * const subformat_lookup[] = {
"STD",
};
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 int 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 int val)
{
if (param_is_interval(n)) {
struct snd_interval *i = param_to_interval(p, n);
i->min = val;
}
}
static unsigned int param_get_min(struct snd_pcm_hw_params *p, int n)
{
if (param_is_interval(n)) {
struct snd_interval *i = param_to_interval(p, n);
return i->min;
}
return 0;
}
static void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned int val)
{
if (param_is_interval(n)) {
struct snd_interval *i = param_to_interval(p, n);
i->max = val;
}
}
static unsigned int param_get_max(struct snd_pcm_hw_params *p, int n)
{
if (param_is_interval(n)) {
struct snd_interval *i = param_to_interval(p, n);
return i->max;
}
return 0;
}
static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int 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 unsigned int param_get_int(struct snd_pcm_hw_params *p, int n)
{
if (param_is_interval(n)) {
struct snd_interval *i = param_to_interval(p, n);
if (i->integer)
return i->max;
}
return 0;
}
static void param_set_flag(struct snd_pcm_hw_params *p, unsigned int flag)
{
if (p != NULL) {
p->flags = flag;
}
}
static int param_get_flag(struct snd_pcm_hw_params *p)
{
if (p != NULL) {
return p->flags;
}
return 0;
}
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;
}
p->rmask = ~0U;
p->cmask = 0;
p->info = ~0U;
}
#define PCM_ERROR_MAX 128
struct pcm {
int fd;
unsigned int flags;
int running:1;
int prepared:1;
int underruns;
unsigned int buffer_size;
unsigned int boundary;
char error[PCM_ERROR_MAX];
struct pcm_config config;
struct snd_pcm_mmap_status *mmap_status;
struct snd_pcm_mmap_control *mmap_control;
struct snd_pcm_sync_ptr *sync_ptr;
void *mmap_buffer;
unsigned int noirq_frames_per_msec;
int wait_for_avail_min;
};
unsigned int pcm_get_buffer_size(struct pcm *pcm)
{
return pcm->buffer_size;
}
const char* pcm_get_error(struct pcm *pcm)
{
return pcm->error;
}
static int oops(struct pcm *pcm, int e, const char *fmt,
评论0