diff --git a/external/cache/sources/tinyalsa_hub/.gitignore b/external/cache/sources/tinyalsa_hub/.gitignore new file mode 100644 index 000000000000..71a12f9067e2 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/.gitignore @@ -0,0 +1,4 @@ +/libtinyalsa.so +/tinycap +/tinymix +/tinyplay diff --git a/external/cache/sources/tinyalsa_hub/Makefile b/external/cache/sources/tinyalsa_hub/Makefile new file mode 100644 index 000000000000..3c0f1bb32207 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/Makefile @@ -0,0 +1,31 @@ +CFLAGS := -c -fPIC $(CFLAGS) +INC = include +OBJECTS = mixer.o pcm.o +LIB = libtinyalsa.so +CC=gcc + +all: $(LIB) tinyplay_hub tinycap_hub tinymix tinypcminfo + cp tinyplay_hub tinycap_hub tinymix tinypcminfo /usr/local/bin + cp libtinyalsa.so /usr/lib/ + +tinyplay_hub: $(LIB) tinyplay_hub.o + $(CC) tinyplay_hub.o -L. -ltinyalsa -o tinyplay_hub + +tinycap_hub: $(LIB) tinycap_hub.o + $(CC) tinycap_hub.o -L. -ltinyalsa -o tinycap_hub + +tinymix: $(LIB) tinymix.o + $(CC) tinymix.o -L. -ltinyalsa -o tinymix + +tinypcminfo: $(LIB) tinypcminfo.o + $(CC) tinypcminfo.o -L. -ltinyalsa -o tinypcminfo + +$(LIB): $(OBJECTS) + $(CC) -shared $(OBJECTS) -o $(LIB) + +.c.o: + $(CC) $(CFLAGS) $< -I$(INC) + +clean: + -rm -f $(LIB) $(OBJECTS) tinyplay_hub.o tinyplay_hub tinycap_hub.o tinycap_hub \ + tinymix.o tinymix tinypcminfo.o tinypcminfo diff --git a/external/cache/sources/tinyalsa_hub/README b/external/cache/sources/tinyalsa_hub/README new file mode 100644 index 000000000000..85b1e5e3bd94 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/README @@ -0,0 +1,9 @@ +tinyalsa: a small library to interface with ALSA in the Linux kernel + +The aims are: + +- Provide a basic pcm and mixer API +- If it's not absolutely needed, don't add it to the API +- Avoid supporting complex and unnecessary operations that could be + dealt with at a higher level + diff --git a/external/cache/sources/tinyalsa_hub/include/sound/asound.h b/external/cache/sources/tinyalsa_hub/include/sound/asound.h new file mode 100644 index 000000000000..a041628ec28e --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/include/sound/asound.h @@ -0,0 +1,821 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __SOUND_ASOUND_H +#define __SOUND_ASOUND_H + +#include + +#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) +#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) +#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) +#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) +#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) + +struct snd_aes_iec958 { + unsigned char status[24]; + unsigned char subcode[147]; + unsigned char pad; + unsigned char dig_subframe[4]; +}; + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, + SNDRV_HWDEP_IFACE_EMU10K1, + SNDRV_HWDEP_IFACE_YSS225, + SNDRV_HWDEP_IFACE_ICS2115, + SNDRV_HWDEP_IFACE_SSCAPE, + SNDRV_HWDEP_IFACE_VX, + SNDRV_HWDEP_IFACE_MIXART, + SNDRV_HWDEP_IFACE_USX2Y, + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, + SNDRV_HWDEP_IFACE_BLUETOOTH, + SNDRV_HWDEP_IFACE_USX2Y_PCM, + SNDRV_HWDEP_IFACE_PCXHR, + SNDRV_HWDEP_IFACE_SB_RC, + SNDRV_HWDEP_IFACE_HDA, + SNDRV_HWDEP_IFACE_USB_STREAM, + + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM +}; + +struct snd_hwdep_info { + unsigned int device; + int card; + unsigned char id[64]; + unsigned char name[80]; + int iface; + unsigned char reserved[64]; +}; + +struct snd_hwdep_dsp_status { + unsigned int version; + unsigned char id[32]; + unsigned int num_dsps; + unsigned int dsp_loaded; + unsigned int chip_ready; + unsigned char reserved[16]; +}; + +struct snd_hwdep_dsp_image { + unsigned int index; + unsigned char name[64]; + unsigned char __user *image; + size_t length; + unsigned long driver_data; +}; + +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) + +typedef unsigned long snd_pcm_uframes_t; +typedef signed long snd_pcm_sframes_t; + +enum { + SNDRV_PCM_CLASS_GENERIC = 0, + SNDRV_PCM_CLASS_MULTI, + SNDRV_PCM_CLASS_MODEM, + SNDRV_PCM_CLASS_DIGITIZER, + + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, + SNDRV_PCM_SUBCLASS_MULTI_MIX, + + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +typedef int __bitwise snd_pcm_access_t; +#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) +#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) +#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) +#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) +#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) +#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED + +typedef int __bitwise snd_pcm_format_t; +#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) +#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) +#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) +#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) +#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) +#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) +#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) +#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) +#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) +#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) +#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) +#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) +#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) +#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) +#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) +#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) +#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) +#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) +#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) +#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) +#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) +#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) +#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) +#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) +#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) +#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) +#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) +#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) +#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) +#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) +#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) +#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) +#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) +#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) +#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) +#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) +#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) +#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) +#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B + +#ifdef SNDRV_LITTLE_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#endif +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#endif + +typedef int __bitwise snd_pcm_subformat_t; +#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD + +#define SNDRV_PCM_INFO_MMAP 0x00000001 +#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 +#define SNDRV_PCM_INFO_DOUBLE 0x00000004 +#define SNDRV_PCM_INFO_BATCH 0x00000010 +#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 +#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 +#define SNDRV_PCM_INFO_COMPLEX 0x00000400 +#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 +#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 +#define SNDRV_PCM_INFO_RESUME 0x00040000 +#define SNDRV_PCM_INFO_PAUSE 0x00080000 +#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 +#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 +#define SNDRV_PCM_INFO_SYNC_START 0x00400000 +#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 +#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 + +typedef int __bitwise snd_pcm_state_t; +#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) +#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) +#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) +#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) +#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) +#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) +#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) +#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) +#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) +#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union snd_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct snd_pcm_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + int dev_class; + int dev_subclass; + unsigned int subdevices_count; + unsigned int subdevices_avail; + union snd_pcm_sync_id sync; + unsigned char reserved[64]; +}; + +typedef int snd_pcm_hw_param_t; +#define SNDRV_PCM_HW_PARAM_ACCESS 0 +#define SNDRV_PCM_HW_PARAM_FORMAT 1 +#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 +#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS +#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT + +#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 +#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 +#define SNDRV_PCM_HW_PARAM_CHANNELS 10 +#define SNDRV_PCM_HW_PARAM_RATE 11 +#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 +#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 +#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 +#define SNDRV_PCM_HW_PARAM_PERIODS 15 +#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 +#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 +#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 +#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 +#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) +#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) + +struct snd_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct snd_mask { + __u32 bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct snd_pcm_hw_params { + unsigned int flags; + struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct snd_mask mres[5]; + struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct snd_interval ires[9]; + unsigned int rmask; + unsigned int cmask; + unsigned int info; + unsigned int msbits; + unsigned int rate_num; + unsigned int rate_den; + snd_pcm_uframes_t fifo_size; + unsigned char reserved[64]; +}; + +enum { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct snd_pcm_sw_params { + int tstamp_mode; + unsigned int period_step; + unsigned int sleep_min; + snd_pcm_uframes_t avail_min; + snd_pcm_uframes_t xfer_align; + snd_pcm_uframes_t start_threshold; + snd_pcm_uframes_t stop_threshold; + snd_pcm_uframes_t silence_threshold; + snd_pcm_uframes_t silence_size; + snd_pcm_uframes_t boundary; + unsigned char reserved[64]; +}; + +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; + unsigned int first; + unsigned int step; +}; + +struct snd_pcm_status { + snd_pcm_state_t state; + struct timespec trigger_tstamp; + struct timespec tstamp; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t hw_ptr; + snd_pcm_sframes_t delay; + snd_pcm_uframes_t avail; + snd_pcm_uframes_t avail_max; + snd_pcm_uframes_t overrange; + snd_pcm_state_t suspended_state; + unsigned char reserved[60]; +}; + +struct snd_pcm_mmap_status { + snd_pcm_state_t state; + int pad1; + snd_pcm_uframes_t hw_ptr; + struct timespec tstamp; + snd_pcm_state_t suspended_state; +}; + +struct snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t avail_min; +}; + +#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) +#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) +#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) + +struct snd_pcm_sync_ptr { + unsigned int flags; + union { + struct snd_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct snd_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct snd_xferi { + snd_pcm_sframes_t result; + void __user *buf; + snd_pcm_uframes_t frames; +}; + +struct snd_xfern { + snd_pcm_sframes_t result; + void __user * __user *bufs; + snd_pcm_uframes_t frames; +}; + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, +}; + +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) + +enum { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 + +struct snd_rawmidi_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned int flags; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; +}; + +struct snd_rawmidi_params { + int stream; + size_t buffer_size; + size_t avail_min; + unsigned int no_active_sensing: 1; + unsigned char reserved[16]; +}; + +struct snd_rawmidi_status { + int stream; + struct timespec tstamp; + size_t avail; + size_t xruns; + unsigned char reserved[16]; +}; + +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +enum { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +enum { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +#define SNDRV_TIMER_GLOBAL_SYSTEM 0 +#define SNDRV_TIMER_GLOBAL_RTC 1 +#define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 + +#define SNDRV_TIMER_FLG_SLAVE (1<<0) + +struct snd_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct snd_timer_ginfo { + struct snd_timer_id tid; + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned long resolution_min; + unsigned long resolution_max; + unsigned int clients; + unsigned char reserved[32]; +}; + +struct snd_timer_gparams { + struct snd_timer_id tid; + unsigned long period_num; + unsigned long period_den; + unsigned char reserved[32]; +}; + +struct snd_timer_gstatus { + struct snd_timer_id tid; + unsigned long resolution; + unsigned long resolution_num; + unsigned long resolution_den; + unsigned char reserved[32]; +}; + +struct snd_timer_select { + struct snd_timer_id id; + unsigned char reserved[32]; +}; + +struct snd_timer_info { + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_PSFLG_AUTO (1<<0) +#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) +#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) + +struct snd_timer_params { + unsigned int flags; + unsigned int ticks; + unsigned int queue_size; + unsigned int reserved0; + unsigned int filter; + unsigned char reserved[60]; +}; + +struct snd_timer_status { + struct timespec tstamp; + unsigned int resolution; + unsigned int lost; + unsigned int overrun; + unsigned int queue; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) + +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) + +struct snd_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum { + SNDRV_TIMER_EVENT_RESOLUTION = 0, + SNDRV_TIMER_EVENT_TICK, + SNDRV_TIMER_EVENT_START, + SNDRV_TIMER_EVENT_STOP, + SNDRV_TIMER_EVENT_CONTINUE, + SNDRV_TIMER_EVENT_PAUSE, + SNDRV_TIMER_EVENT_EARLY, + SNDRV_TIMER_EVENT_SUSPEND, + SNDRV_TIMER_EVENT_RESUME, + + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +struct snd_timer_tread { + int event; + struct timespec tstamp; + unsigned int val; +}; + +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +struct snd_ctl_card_info { + int card; + int pad; + unsigned char id[16]; + unsigned char driver[16]; + unsigned char name[32]; + unsigned char longname[80]; + unsigned char reserved_[16]; + unsigned char mixername[80]; + unsigned char components[128]; +}; + +typedef int __bitwise snd_ctl_elem_type_t; +#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) +#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) +#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) +#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) +#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) +#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) +#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) +#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 + +typedef int __bitwise snd_ctl_elem_iface_t; +#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) +#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) +#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) +#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) +#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) +#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) +#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) +#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) +#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) +#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) +#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) +#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) + +#define SNDRV_CTL_POWER_D0 0x0000 +#define SNDRV_CTL_POWER_D1 0x0100 +#define SNDRV_CTL_POWER_D2 0x0200 +#define SNDRV_CTL_POWER_D3 0x0300 +#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) +#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) + +struct snd_ctl_elem_id { + unsigned int numid; + snd_ctl_elem_iface_t iface; + unsigned int device; + unsigned int subdevice; + unsigned char name[44]; + unsigned int index; +}; + +struct snd_ctl_elem_list { + unsigned int offset; + unsigned int space; + unsigned int used; + unsigned int count; + struct snd_ctl_elem_id __user *pids; + unsigned char reserved[50]; +}; + +struct snd_ctl_elem_info { + struct snd_ctl_elem_id id; + snd_ctl_elem_type_t type; + unsigned int access; + unsigned int count; + __kernel_pid_t owner; + union { + struct { + long min; + long max; + long step; + } integer; + struct { + long long min; + long long max; + long long step; + } integer64; + struct { + unsigned int items; + unsigned int item; + char name[64]; + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; + unsigned short *d_ptr; + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct snd_ctl_elem_value { + struct snd_ctl_elem_id id; + unsigned int indirect: 1; + union { + union { + long value[128]; + long *value_ptr; + } integer; + union { + long long value[64]; + long long *value_ptr; + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; + } bytes; + struct snd_aes_iec958 iec958; + } value; + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct snd_ctl_tlv { + unsigned int numid; + unsigned int length; + unsigned int tlv[0]; +}; + +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) +#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) +#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) +#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) + +struct snd_ctl_event { + int type; + union { + struct { + unsigned int mask; + struct snd_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +#define SNDRV_CTL_NAME_NONE "" +#define SNDRV_CTL_NAME_PLAYBACK "Playback " +#define SNDRV_CTL_NAME_CAPTURE "Capture " + +#define SNDRV_CTL_NAME_IEC958_NONE "" +#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" +#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" +#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" +#define SNDRV_CTL_NAME_IEC958_MASK "Mask" +#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" +#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what + +#endif + diff --git a/external/cache/sources/tinyalsa_hub/include/tinyalsa/asoundlib.h b/external/cache/sources/tinyalsa_hub/include/tinyalsa/asoundlib.h new file mode 100644 index 000000000000..9d2e2d6ee602 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/include/tinyalsa/asoundlib.h @@ -0,0 +1,261 @@ +/* asoundlib.h +** +** 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. +*/ + +#ifndef ASOUNDLIB_H +#define ASOUNDLIB_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * PCM API + */ + +struct pcm; + +#define PCM_OUT 0x00000000 +#define PCM_IN 0x10000000 +#define PCM_MMAP 0x00000001 +#define PCM_NOIRQ 0x00000002 +#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to + * pcm_write for a playback stream will not + * attempt to restart the stream in the case + * of an underflow, but will return -EPIPE + * instead. After the first -EPIPE error, the + * stream is considered to be stopped, and a + * second call to pcm_write will attempt to + * restart the stream. + */ +#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */ + +/* PCM runtime states */ +#define PCM_STATE_RUNNING 3 +#define PCM_STATE_XRUN 4 +#define PCM_STATE_DRAINING 5 +#define PCM_STATE_SUSPENDED 7 +#define PCM_STATE_DISCONNECTED 8 + +/* Bit formats */ +enum pcm_format { + PCM_FORMAT_S16_LE = 0, + PCM_FORMAT_S32_LE, + PCM_FORMAT_S8, + PCM_FORMAT_S24_LE, + + PCM_FORMAT_MAX, +}; + +/* Bitmask has 256 bits (32 bytes) in asound.h */ +struct pcm_mask { + unsigned int bits[32 / sizeof(unsigned int)]; +}; + +/* Configuration for a stream */ +struct pcm_config { + unsigned int channels; + unsigned int rate; + unsigned int period_size; + unsigned int period_count; + enum pcm_format format; + + /* Values to use for the ALSA start, stop and silence thresholds. Setting + * any one of these values to 0 will cause the default tinyalsa values to be + * used instead. Tinyalsa defaults are as follows. + * + * start_threshold : period_count * period_size + * stop_threshold : period_count * period_size + * silence_threshold : 0 + */ + unsigned int start_threshold; + unsigned int stop_threshold; + unsigned int silence_threshold; +}; + +/* PCM parameters */ +enum pcm_param +{ + /* mask parameters */ + PCM_PARAM_ACCESS, + PCM_PARAM_FORMAT, + PCM_PARAM_SUBFORMAT, + /* interval parameters */ + PCM_PARAM_SAMPLE_BITS, + PCM_PARAM_FRAME_BITS, + PCM_PARAM_CHANNELS, + PCM_PARAM_RATE, + PCM_PARAM_PERIOD_TIME, + PCM_PARAM_PERIOD_SIZE, + PCM_PARAM_PERIOD_BYTES, + PCM_PARAM_PERIODS, + PCM_PARAM_BUFFER_TIME, + PCM_PARAM_BUFFER_SIZE, + PCM_PARAM_BUFFER_BYTES, + PCM_PARAM_TICK_TIME, +}; + +/* Mixer control types */ +enum mixer_ctl_type { + MIXER_CTL_TYPE_BOOL, + MIXER_CTL_TYPE_INT, + MIXER_CTL_TYPE_ENUM, + MIXER_CTL_TYPE_BYTE, + MIXER_CTL_TYPE_IEC958, + MIXER_CTL_TYPE_INT64, + MIXER_CTL_TYPE_UNKNOWN, + + MIXER_CTL_TYPE_MAX, +}; + +/* Open and close a stream */ +struct pcm *pcm_open(unsigned int card, unsigned int device, + unsigned int flags, struct pcm_config *config); +int pcm_close(struct pcm *pcm); +int pcm_is_ready(struct pcm *pcm); + +/* Obtain the parameters for a PCM */ +struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, + unsigned int flags); +void pcm_params_free(struct pcm_params *pcm_params); + +struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params, + enum pcm_param param); +unsigned int pcm_params_get_min(struct pcm_params *pcm_params, + enum pcm_param param); +unsigned int pcm_params_get_max(struct pcm_params *pcm_params, + enum pcm_param param); + +/* Returns a human readable reason for the last error */ +const char *pcm_get_error(struct pcm *pcm); + +/* Returns the sample size in bits for a PCM format. + * As with ALSA formats, this is the storage size for the format, whereas the + * format represents the number of significant bits. For example, + * PCM_FORMAT_S24_LE uses 32 bits of storage. + */ +unsigned int pcm_format_to_bits(enum pcm_format format); + +/* Returns the buffer size (int frames) that should be used for pcm_write. */ +unsigned int pcm_get_buffer_size(struct pcm *pcm); +unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames); +unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes); + +/* Returns available frames in pcm buffer and corresponding time stamp. + * The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open, + * otherwise the clock is CLOCK_REALTIME. + * For an input stream, frames available are frames ready for the + * application to read. + * For an output stream, frames available are the number of empty frames available + * for the application to write. + */ +int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, + struct timespec *tstamp); + +/* Write data to the fifo. + * Will start playback on the first write or on a write that + * occurs after a fifo underrun. + */ +int pcm_write(struct pcm *pcm, const void *data, unsigned int count); +int pcm_read(struct pcm *pcm, void *data, unsigned int count); + +/* + * mmap() support. + */ +int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count); +int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count); +int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, + unsigned int *frames); +int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); + +int pcm_resume(struct pcm *pcm); +/* Prepare the PCM substream to be triggerable */ +int pcm_prepare(struct pcm *pcm); +/* Start and stop a PCM channel that doesn't transfer data */ +int pcm_start(struct pcm *pcm); +int pcm_stop(struct pcm *pcm); + +/* Interrupt driven API */ +int pcm_wait(struct pcm *pcm, int timeout); + + +/* + * MIXER API + */ + +struct mixer; +struct mixer_ctl; + +/* Open and close a mixer */ +struct mixer *mixer_open(unsigned int card); +void mixer_close(struct mixer *mixer); + +/* Get info about a mixer */ +const char *mixer_get_name(struct mixer *mixer); + +/* Obtain mixer controls */ +unsigned int mixer_get_num_ctls(struct mixer *mixer); +struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id); +struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name); + +/* Get info about mixer controls */ +const char *mixer_ctl_get_name(struct mixer_ctl *ctl); +enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl); +const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl); +unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl); +unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl); +const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, + unsigned int enum_id); + +/* Some sound cards update their controls due to external events, + * such as HDMI EDID byte data changing when an HDMI cable is + * connected. This API allows the count of elements to be updated. + */ +void mixer_ctl_update(struct mixer_ctl *ctl); + +/* Set and get mixer controls */ +int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id); +int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent); + +int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id); +int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count); +int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value); +int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count); +int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string); + +/* Determe range of integer mixer controls */ +int mixer_ctl_get_range_min(struct mixer_ctl *ctl); +int mixer_ctl_get_range_max(struct mixer_ctl *ctl); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif diff --git a/external/cache/sources/tinyalsa_hub/mixer.c b/external/cache/sources/tinyalsa_hub/mixer.c new file mode 100644 index 000000000000..78b1a12a04ec --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/mixer.c @@ -0,0 +1,503 @@ +/* mixer.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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#define __force +#define __bitwise +#define __user +#include + +#include + +struct mixer_ctl { + struct mixer *mixer; + struct snd_ctl_elem_info *info; + char **ename; +}; + +struct mixer { + int fd; + struct snd_ctl_card_info card_info; + struct snd_ctl_elem_info *elem_info; + struct mixer_ctl *ctl; + unsigned int count; +}; + +void mixer_close(struct mixer *mixer) +{ + unsigned int n,m; + + if (!mixer) + return; + + if (mixer->fd >= 0) + close(mixer->fd); + + if (mixer->ctl) { + for (n = 0; n < mixer->count; n++) { + if (mixer->ctl[n].ename) { + unsigned int max = mixer->ctl[n].info->value.enumerated.items; + for (m = 0; m < max; m++) + free(mixer->ctl[n].ename[m]); + free(mixer->ctl[n].ename); + } + } + free(mixer->ctl); + } + + if (mixer->elem_info) + free(mixer->elem_info); + + free(mixer); + + /* TODO: verify frees */ +} + +struct mixer *mixer_open(unsigned int card) +{ + struct snd_ctl_elem_list elist; + struct snd_ctl_elem_info tmp; + struct snd_ctl_elem_id *eid = NULL; + struct mixer *mixer = NULL; + unsigned int n, m; + int fd; + char fn[256]; + + snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); + fd = open(fn, O_RDWR); + if (fd < 0) + return 0; + + memset(&elist, 0, sizeof(elist)); + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + mixer = calloc(1, sizeof(*mixer)); + if (!mixer) + goto fail; + + mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); + mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); + if (!mixer->ctl || !mixer->elem_info) + goto fail; + + if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) + goto fail; + + eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); + if (!eid) + goto fail; + + mixer->count = elist.count; + mixer->fd = fd; + elist.space = mixer->count; + elist.pids = eid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + for (n = 0; n < mixer->count; n++) { + struct snd_ctl_elem_info *ei = mixer->elem_info + n; + ei->id.numid = eid[n].numid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) + goto fail; + mixer->ctl[n].info = ei; + mixer->ctl[n].mixer = mixer; + if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); + if (!enames) + goto fail; + mixer->ctl[n].ename = enames; + for (m = 0; m < ei->value.enumerated.items; m++) { + memset(&tmp, 0, sizeof(tmp)); + tmp.id.numid = ei->id.numid; + tmp.value.enumerated.item = m; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) + goto fail; + enames[m] = strdup(tmp.value.enumerated.name); + if (!enames[m]) + goto fail; + } + } + } + + free(eid); + return mixer; + +fail: + /* TODO: verify frees in failure case */ + if (eid) + free(eid); + if (mixer) + mixer_close(mixer); + else if (fd >= 0) + close(fd); + return 0; +} + +const char *mixer_get_name(struct mixer *mixer) +{ + return (const char *)mixer->card_info.name; +} + +unsigned int mixer_get_num_ctls(struct mixer *mixer) +{ + if (!mixer) + return 0; + + return mixer->count; +} + +struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id) +{ + if (mixer && (id < mixer->count)) + return mixer->ctl + id; + + return NULL; +} + +struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name) +{ + unsigned int n; + + if (!mixer) + return NULL; + + for (n = 0; n < mixer->count; n++) + if (!strcmp(name, (char*) mixer->elem_info[n].id.name)) + return mixer->ctl + n; + + return NULL; +} + +void mixer_ctl_update(struct mixer_ctl *ctl) +{ + ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); +} + +const char *mixer_ctl_get_name(struct mixer_ctl *ctl) +{ + if (!ctl) + return NULL; + + return (const char *)ctl->info->id.name; +} + +enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl) +{ + if (!ctl) + return MIXER_CTL_TYPE_UNKNOWN; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL; + case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM; + case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE; + case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64; + default: return MIXER_CTL_TYPE_UNKNOWN; + }; +} + +const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl) +{ + if (!ctl) + return ""; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL"; + case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT"; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM"; + case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE"; + case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958"; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64"; + default: return "Unknown"; + }; +} + +unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl) +{ + if (!ctl) + return 0; + + return ctl->info->count; +} + +static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) +{ + if ((percent > 100) || (percent < 0)) { + return -EINVAL; + } + + int range = (ei->value.integer.max - ei->value.integer.min); + + return ei->value.integer.min + (range * percent) / 100; +} + +static int int_to_percent(struct snd_ctl_elem_info *ei, int value) +{ + int range = (ei->value.integer.max - ei->value.integer.min); + + if (range == 0) + return 0; + + return ((value - ei->value.integer.min) / range) * 100; +} + +int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id)); +} + +int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent)); +} + +int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (id >= ctl->info->count)) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + return !!ev.value.integer.value[id]; + + case SNDRV_CTL_ELEM_TYPE_INTEGER: + return ev.value.integer.value[id]; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + return ev.value.enumerated.item[id]; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + return ev.value.bytes.data[id]; + + default: + return -EINVAL; + } + + return 0; +} + +int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) +{ + struct snd_ctl_elem_value ev; + int ret; + size_t size; + void *source; + + if (!ctl || (count > ctl->info->count) || !count || !array) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + size = sizeof(ev.value.integer.value[0]); + source = ev.value.integer.value; + break; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + size = sizeof(ev.value.bytes.data[0]); + source = ev.value.bytes.data; + break; + + default: + return -EINVAL; + } + + memcpy(array, source, size * count); + + return 0; +} + +int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (id >= ctl->info->count)) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + ev.value.integer.value[id] = !!value; + break; + + case SNDRV_CTL_ELEM_TYPE_INTEGER: + if ((value < mixer_ctl_get_range_min(ctl)) || + (value > mixer_ctl_get_range_max(ctl))) { + return -EINVAL; + } + + ev.value.integer.value[id] = value; + break; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + ev.value.enumerated.item[id] = value; + break; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + ev.value.bytes.data[id] = value; + break; + + default: + return -EINVAL; + } + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) +{ + struct snd_ctl_elem_value ev; + size_t size; + void *dest; + + if (!ctl || (count > ctl->info->count) || !count || !array) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + size = sizeof(ev.value.integer.value[0]); + dest = ev.value.integer.value; + break; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + size = sizeof(ev.value.bytes.data[0]); + dest = ev.value.bytes.data; + break; + + default: + return -EINVAL; + } + + memcpy(dest, array, size * count); + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_get_range_min(struct mixer_ctl *ctl) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return ctl->info->value.integer.min; +} + +int mixer_ctl_get_range_max(struct mixer_ctl *ctl) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return ctl->info->value.integer.max; +} + +unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl) +{ + if (!ctl) + return 0; + + return ctl->info->value.enumerated.items; +} + +const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, + unsigned int enum_id) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) || + (enum_id >= ctl->info->value.enumerated.items)) + return NULL; + + return (const char *)ctl->ename[enum_id]; +} + +int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string) +{ + unsigned int i, num_enums; + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)) + return -EINVAL; + + num_enums = ctl->info->value.enumerated.items; + for (i = 0; i < num_enums; i++) { + if (!strcmp(string, ctl->ename[i])) { + memset(&ev, 0, sizeof(ev)); + ev.value.enumerated.item[0] = i; + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); + if (ret < 0) + return ret; + return 0; + } + } + + return -EINVAL; +} + diff --git a/external/cache/sources/tinyalsa_hub/pcm.c b/external/cache/sources/tinyalsa_hub/pcm.c new file mode 100644 index 000000000000..a8d18c204d0b --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/pcm.c @@ -0,0 +1,1050 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#define __force +#define __bitwise +#define __user +#include + +#include + +#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) + +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 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_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; +}; + +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, ...) +{ + 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; +} + +static unsigned int pcm_format_to_alsa(enum pcm_format format) +{ + switch (format) { + case PCM_FORMAT_S32_LE: + return SNDRV_PCM_FORMAT_S32_LE; + case PCM_FORMAT_S8: + return SNDRV_PCM_FORMAT_S8; + case PCM_FORMAT_S24_LE: + return SNDRV_PCM_FORMAT_S24_LE; + default: + case PCM_FORMAT_S16_LE: + return SNDRV_PCM_FORMAT_S16_LE; + }; +} + +unsigned int pcm_format_to_bits(enum pcm_format format) +{ + switch (format) { + case PCM_FORMAT_S32_LE: + case PCM_FORMAT_S24_LE: + return 32; + default: + case PCM_FORMAT_S16_LE: + return 16; + }; +} + +unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) +{ + return bytes / (pcm->config.channels * + (pcm_format_to_bits(pcm->config.format) >> 3)); +} + +unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) +{ + return frames * pcm->config.channels * + (pcm_format_to_bits(pcm->config.format) >> 3); +} + +static int pcm_sync_ptr(struct pcm *pcm, int flags) { + if (pcm->sync_ptr) { + pcm->sync_ptr->flags = flags; + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) + return -1; + } + return 0; +} + +static int pcm_hw_mmap_status(struct pcm *pcm) { + + if (pcm->sync_ptr) + return 0; + + int page_size = sysconf(_SC_PAGE_SIZE); + pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, + pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + if (pcm->mmap_status == MAP_FAILED) + pcm->mmap_status = NULL; + if (!pcm->mmap_status) + goto mmap_error; + + pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (pcm->mmap_control == MAP_FAILED) + pcm->mmap_control = NULL; + if (!pcm->mmap_control) { + munmap(pcm->mmap_status, page_size); + pcm->mmap_status = NULL; + goto mmap_error; + } + pcm->mmap_control->avail_min = 1; + + return 0; + +mmap_error: + + pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); + if (!pcm->sync_ptr) + return -ENOMEM; + pcm->mmap_status = &pcm->sync_ptr->s.status; + pcm->mmap_control = &pcm->sync_ptr->c.control; + pcm->mmap_control->avail_min = 1; + pcm_sync_ptr(pcm, 0); + + return 0; +} + +static void pcm_hw_munmap_status(struct pcm *pcm) { + if (pcm->sync_ptr) { + free(pcm->sync_ptr); + pcm->sync_ptr = NULL; + } else { + int page_size = sysconf(_SC_PAGE_SIZE); + if (pcm->mmap_status) + munmap(pcm->mmap_status, page_size); + if (pcm->mmap_control) + munmap(pcm->mmap_control, page_size); + } + pcm->mmap_status = NULL; + pcm->mmap_control = NULL; +} + +static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, + char *buf, unsigned int src_offset, + unsigned int frames) +{ + int size_bytes = pcm_frames_to_bytes(pcm, frames); + int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); + int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); + + /* interleaved only atm */ + if (pcm->flags & PCM_IN) + memcpy(buf + src_offset_bytes, + (char*)pcm->mmap_buffer + pcm_offset_bytes, + size_bytes); + else + memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, + buf + src_offset_bytes, + size_bytes); + return 0; +} + +static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf, + unsigned int offset, unsigned int size) +{ + void *pcm_areas; + int commit; + unsigned int pcm_offset, frames, count = 0; + + while (size > 0) { + frames = size; + pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); + pcm_areas_copy(pcm, pcm_offset, buf, offset, frames); + commit = pcm_mmap_commit(pcm, pcm_offset, frames); + if (commit < 0) { + oops(pcm, commit, "failed to commit %d frames\n", frames); + return commit; + } + + offset += commit; + count += commit; + size -= commit; + } + return count; +} + +int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, + struct timespec *tstamp) +{ + int frames; + int rc; + snd_pcm_uframes_t hw_ptr; + + if (!pcm_is_ready(pcm)) + return -1; + + rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); + if (rc < 0) + return -1; + + if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && + (pcm->mmap_status->state != PCM_STATE_DRAINING)) + return -1; + + *tstamp = pcm->mmap_status->tstamp; + if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0) + return -1; + + hw_ptr = pcm->mmap_status->hw_ptr; + if (pcm->flags & PCM_IN) + frames = hw_ptr - pcm->mmap_control->appl_ptr; + else + frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; + + if (frames < 0) + return -1; + + *avail = (unsigned int)frames; + + return 0; +} + +int pcm_write(struct pcm *pcm, const void *data, unsigned int count) +{ + struct snd_xferi x; + + if (pcm->flags & PCM_IN) + return -EINVAL; + + x.buf = (void*)data; + x.frames = count / (pcm->config.channels * + pcm_format_to_bits(pcm->config.format) / 8); + + for (;;) { + if (!pcm->running) { + int prepare_error = pcm_prepare(pcm); + if (prepare_error) + return prepare_error; + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + printf("[%s]-->line:%d,errno:%d\n", __func__, __LINE__, errno); + return oops(pcm, errno, "cannot write initial data"); + } + pcm->running = 1; + return 0; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + pcm->prepared = 0; + pcm->running = 0; + printf("[%s]-->line:%d,errno:%d\n", __func__, __LINE__, errno); + if (errno == EPIPE) { + /* we failed to make our window -- try to restart if we are + * allowed to do so. Otherwise, simply allow the EPIPE error to + * propagate up to the app level */ + pcm->underruns++; + if (pcm->flags & PCM_NORESTART) + return -EPIPE; + continue; + } + return oops(pcm, errno, "cannot write stream data"); + } + return 0; + } +} + +int pcm_read(struct pcm *pcm, void *data, unsigned int count) +{ + struct snd_xferi x; + + if (!(pcm->flags & PCM_IN)) + return -EINVAL; + + x.buf = data; + x.frames = count / (pcm->config.channels * + pcm_format_to_bits(pcm->config.format) / 8); + + for (;;) { + if (!pcm->running) { + if (pcm_start(pcm) < 0) { + fprintf(stderr, "start error"); + return -errno; + } + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { + pcm->prepared = 0; + pcm->running = 0; + printf("[%s]-->line:%d,errno:%d\n", __func__, __LINE__, errno); + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot read stream data"); + } + return 0; + } +} + +static struct pcm bad_pcm = { + .fd = -1, +}; + +struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, + unsigned int flags) +{ + struct snd_pcm_hw_params *params; + char fn[256]; + int fd; + + snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, + flags & PCM_IN ? 'c' : 'p'); + + fd = open(fn, O_RDWR); + if (fd < 0) { + fprintf(stderr, "cannot open device '%s'\n", fn); + goto err_open; + } + + params = calloc(1, sizeof(struct snd_pcm_hw_params)); + if (!params) + goto err_calloc; + + param_init(params); + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { + fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); + goto err_hw_refine; + } + + close(fd); + + return (struct pcm_params *)params; + +err_hw_refine: + free(params); +err_calloc: + close(fd); +err_open: + return NULL; +} + +void pcm_params_free(struct pcm_params *pcm_params) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + + if (params) + free(params); +} + +static int pcm_param_to_alsa(enum pcm_param param) +{ + switch (param) { + case PCM_PARAM_ACCESS: + return SNDRV_PCM_HW_PARAM_ACCESS; + case PCM_PARAM_FORMAT: + return SNDRV_PCM_HW_PARAM_FORMAT; + case PCM_PARAM_SUBFORMAT: + return SNDRV_PCM_HW_PARAM_SUBFORMAT; + case PCM_PARAM_SAMPLE_BITS: + return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; + break; + case PCM_PARAM_FRAME_BITS: + return SNDRV_PCM_HW_PARAM_FRAME_BITS; + break; + case PCM_PARAM_CHANNELS: + return SNDRV_PCM_HW_PARAM_CHANNELS; + break; + case PCM_PARAM_RATE: + return SNDRV_PCM_HW_PARAM_RATE; + break; + case PCM_PARAM_PERIOD_TIME: + return SNDRV_PCM_HW_PARAM_PERIOD_TIME; + break; + case PCM_PARAM_PERIOD_SIZE: + return SNDRV_PCM_HW_PARAM_PERIOD_SIZE; + break; + case PCM_PARAM_PERIOD_BYTES: + return SNDRV_PCM_HW_PARAM_PERIOD_BYTES; + break; + case PCM_PARAM_PERIODS: + return SNDRV_PCM_HW_PARAM_PERIODS; + break; + case PCM_PARAM_BUFFER_TIME: + return SNDRV_PCM_HW_PARAM_BUFFER_TIME; + break; + case PCM_PARAM_BUFFER_SIZE: + return SNDRV_PCM_HW_PARAM_BUFFER_SIZE; + break; + case PCM_PARAM_BUFFER_BYTES: + return SNDRV_PCM_HW_PARAM_BUFFER_BYTES; + break; + case PCM_PARAM_TICK_TIME: + return SNDRV_PCM_HW_PARAM_TICK_TIME; + break; + + default: + return -1; + } +} + +struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params, + enum pcm_param param) +{ + int p; + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + if (params == NULL) { + return NULL; + } + + p = pcm_param_to_alsa(param); + if (p < 0 || !param_is_mask(p)) { + return NULL; + } + + return (struct pcm_mask *)param_to_mask(params, p); +} + +unsigned int pcm_params_get_min(struct pcm_params *pcm_params, + enum pcm_param param) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + int p; + + if (!params) + return 0; + + p = pcm_param_to_alsa(param); + if (p < 0) + return 0; + + return param_get_min(params, p); +} + +unsigned int pcm_params_get_max(struct pcm_params *pcm_params, + enum pcm_param param) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + int p; + + if (!params) + return 0; + + p = pcm_param_to_alsa(param); + if (p < 0) + return 0; + + return param_get_max(params, p); +} + +int pcm_close(struct pcm *pcm) +{ + if (pcm == &bad_pcm) + return 0; + + pcm_hw_munmap_status(pcm); + + if (pcm->flags & PCM_MMAP) { + pcm_stop(pcm); + munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); + } + + if (pcm->fd >= 0) + close(pcm->fd); + pcm->prepared = 0; + pcm->running = 0; + pcm->buffer_size = 0; + pcm->fd = -1; + free(pcm); + return 0; +} + +struct pcm *pcm_open(unsigned int card, unsigned int device, + unsigned int flags, struct pcm_config *config) +{ + struct pcm *pcm; + struct snd_pcm_info info; + struct snd_pcm_hw_params params; + struct snd_pcm_sw_params sparams; + char fn[256]; + int rc; + + pcm = calloc(1, sizeof(struct pcm)); + if (!pcm || !config) + return &bad_pcm; /* TODO: could support default config here */ + + pcm->config = *config; + + snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, + flags & PCM_IN ? 'c' : 'p'); + + pcm->flags = flags; + pcm->fd = open(fn, O_RDWR); + if (pcm->fd < 0) { + oops(pcm, errno, "cannot open device '%s'", fn); + return pcm; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { + oops(pcm, errno, "cannot get info"); + goto fail_close; + } + + param_init(¶ms); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, + pcm_format_to_alsa(config->format)); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + pcm_format_to_bits(config->format)); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, + pcm_format_to_bits(config->format) * config->channels); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, + config->channels); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); + + if (flags & PCM_NOIRQ) { + + if (!(flags & PCM_MMAP)) { + oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); + goto fail; + } + + params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; + pcm->noirq_frames_per_msec = config->rate / 1000; + } + + if (flags & PCM_MMAP) + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); + else + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_RW_INTERLEAVED); + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { + oops(pcm, errno, "cannot set hw params"); + goto fail_close; + } + + /* get our refined hw_params */ + config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); + pcm->buffer_size = config->period_count * config->period_size; + + if (flags & PCM_MMAP) { + pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), + PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); + if (pcm->mmap_buffer == MAP_FAILED) { + oops(pcm, -errno, "failed to mmap buffer %d bytes\n", + pcm_frames_to_bytes(pcm, pcm->buffer_size)); + goto fail_close; + } + } + + + memset(&sparams, 0, sizeof(sparams)); + sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; + sparams.period_step = 1; + sparams.avail_min = 1; + + if (!config->start_threshold) { + if (pcm->flags & PCM_IN) + pcm->config.start_threshold = sparams.start_threshold = 1; + else + pcm->config.start_threshold = sparams.start_threshold = + config->period_count * config->period_size / 2; + } else + sparams.start_threshold = config->start_threshold; + + /* pick a high stop threshold - todo: does this need further tuning */ + if (!config->stop_threshold) { + if (pcm->flags & PCM_IN) + pcm->config.stop_threshold = sparams.stop_threshold = + config->period_count * config->period_size * 10; + else + pcm->config.stop_threshold = sparams.stop_threshold = + config->period_count * config->period_size; + } + else + sparams.stop_threshold = config->stop_threshold; + + sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ + sparams.silence_size = 0; + sparams.silence_threshold = config->silence_threshold; + pcm->boundary = sparams.boundary = pcm->buffer_size; + + while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) + pcm->boundary *= 2; + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { + oops(pcm, errno, "cannot set sw params"); + goto fail; + } + + rc = pcm_hw_mmap_status(pcm); + if (rc < 0) { + oops(pcm, rc, "mmap status failed"); + goto fail; + } + +#ifdef SNDRV_PCM_IOCTL_TTSTAMP + if (pcm->flags & PCM_MONOTONIC) { + int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; + rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); + if (rc < 0) { + oops(pcm, rc, "cannot set timestamp type"); + goto fail; + } + } +#endif + + pcm->underruns = 0; + return pcm; + +fail: + if (flags & PCM_MMAP) + munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); +fail_close: + close(pcm->fd); + pcm->fd = -1; + return pcm; +} + +int pcm_is_ready(struct pcm *pcm) +{ + return pcm->fd >= 0; +} + +int pcm_prepare(struct pcm *pcm) +{ + if (pcm->prepared) + return 0; + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) + return oops(pcm, errno, "cannot prepare channel"); + + pcm->prepared = 1; + return 0; +} + +int pcm_start(struct pcm *pcm) +{ + int prepare_error = pcm_prepare(pcm); + if (prepare_error) + return prepare_error; + + if (pcm->flags & PCM_MMAP) + pcm_sync_ptr(pcm, 0); + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) + return oops(pcm, errno, "cannot start channel"); + + pcm->running = 1; + return 0; +} + +int pcm_stop(struct pcm *pcm) +{ + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) + return oops(pcm, errno, "cannot stop channel"); + + pcm->prepared = 0; + pcm->running = 0; + return 0; +} + +static inline int pcm_mmap_playback_avail(struct pcm *pcm) +{ + int avail; + + avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; + + if (avail < 0) + avail += pcm->boundary; + else if (avail > (int)pcm->boundary) + avail -= pcm->boundary; + + return avail; +} + +static inline int pcm_mmap_capture_avail(struct pcm *pcm) +{ + int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; + if (avail < 0) + avail += pcm->boundary; + return avail; +} + +static inline int pcm_mmap_avail(struct pcm *pcm) +{ + pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); + if (pcm->flags & PCM_IN) + return pcm_mmap_capture_avail(pcm); + else + return pcm_mmap_playback_avail(pcm); +} + +static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) +{ + unsigned int appl_ptr = pcm->mmap_control->appl_ptr; + appl_ptr += frames; + + /* check for boundary wrap */ + if (appl_ptr > pcm->boundary) + appl_ptr -= pcm->boundary; + pcm->mmap_control->appl_ptr = appl_ptr; +} + +int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, + unsigned int *frames) +{ + unsigned int continuous, copy_frames, avail; + + /* return the mmap buffer */ + *areas = pcm->mmap_buffer; + + /* and the application offset in frames */ + *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; + + avail = pcm_mmap_avail(pcm); + if (avail > pcm->buffer_size) + avail = pcm->buffer_size; + continuous = pcm->buffer_size - *offset; + + /* we can only copy frames if the are availabale and continuos */ + copy_frames = *frames; + if (copy_frames > avail) + copy_frames = avail; + if (copy_frames > continuous) + copy_frames = continuous; + *frames = copy_frames; + + return 0; +} + +int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) +{ + /* update the application pointer in userspace and kernel */ + pcm_mmap_appl_forward(pcm, frames); + pcm_sync_ptr(pcm, 0); + + return frames; +} + +int pcm_avail_update(struct pcm *pcm) +{ + pcm_sync_ptr(pcm, 0); + return pcm_mmap_avail(pcm); +} + +int pcm_state(struct pcm *pcm) +{ + int err = pcm_sync_ptr(pcm, 0); + if (err < 0) + return err; + + return pcm->mmap_status->state; +} + +int pcm_wait(struct pcm *pcm, int timeout) +{ + struct pollfd pfd; + int err; + + pfd.fd = pcm->fd; + pfd.events = POLLOUT | POLLERR | POLLNVAL; + + do { + /* let's wait for avail or timeout */ + err = poll(&pfd, 1, timeout); + if (err < 0) + return -errno; + + /* timeout ? */ + if (err == 0) + return 0; + + /* have we been interrupted ? */ + if (errno == -EINTR) + continue; + + /* check for any errors */ + if (pfd.revents & (POLLERR | POLLNVAL)) { + switch (pcm_state(pcm)) { + case PCM_STATE_XRUN: + return -EPIPE; + case PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EIO; + } + } + /* poll again if fd not ready for IO */ + } while (!(pfd.revents & (POLLIN | POLLOUT))); + + return 1; +} + +int pcm_mmap_transfer(struct pcm *pcm, const void *buffer, unsigned int bytes) +{ + int err = 0, frames, avail; + unsigned int offset = 0, count; + + if (bytes == 0) + return 0; + + count = pcm_bytes_to_frames(pcm, bytes); + + while (count > 0) { + + /* get the available space for writing new frames */ + avail = pcm_avail_update(pcm); + if (avail < 0) { + fprintf(stderr, "cannot determine available mmap frames"); + return err; + } + + /* start the audio if we reach the threshold */ + if (!pcm->running && + (pcm->buffer_size - avail) >= pcm->config.start_threshold) { + if (pcm_start(pcm) < 0) { + fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + return -errno; + } + } + + /* sleep until we have space to write new frames */ + if (pcm->running && + (unsigned int)avail < pcm->mmap_control->avail_min) { + int time = -1; + + if (pcm->flags & PCM_NOIRQ) + time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min) + / pcm->noirq_frames_per_msec; + + err = pcm_wait(pcm, time); + if (err < 0) { + pcm->prepared = 0; + pcm->running = 0; + fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + pcm->mmap_control->appl_ptr = 0; + return err; + } + continue; + } + + frames = count; + if (frames > avail) + frames = avail; + + if (!frames) + break; + + /* copy frames from buffer */ + frames = pcm_mmap_transfer_areas(pcm, (void *)buffer, offset, frames); + if (frames < 0) { + fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + return frames; + } + + offset += frames; + count -= frames; + } + + return 0; +} + +int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count) +{ + if ((~pcm->flags) & (PCM_OUT | PCM_MMAP)) + return -ENOSYS; + + return pcm_mmap_transfer(pcm, (void *)data, count); +} + +int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count) +{ + if ((~pcm->flags) & (PCM_IN | PCM_MMAP)) + return -ENOSYS; + + return pcm_mmap_transfer(pcm, data, count); +} diff --git a/external/cache/sources/tinyalsa_hub/tinycap_hub.c b/external/cache/sources/tinyalsa_hub/tinycap_hub.c new file mode 100644 index 000000000000..6c60856ff5d4 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/tinycap_hub.c @@ -0,0 +1,288 @@ +/* tinycap.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 +#include +#include +#include +#include +#include + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +#define FORMAT_PCM 1 + +struct wav_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t riff_fmt; + uint32_t fmt_id; + uint32_t fmt_sz; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + uint32_t data_id; + uint32_t data_sz; +}; + +int loop_seconds = 0; +int capturing = 1; +int prinfo = 1; + +unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, + unsigned int channels, unsigned int rate, + enum pcm_format format, unsigned int period_size, + unsigned int period_count); + +void sigint_handler(int sig) +{ + capturing = 0; +} + +int main(int argc, char **argv) +{ + FILE *file; + struct wav_header header; + unsigned int card = 0; + unsigned int device = 0; + unsigned int channels = 2; + unsigned int rate = 44100; + unsigned int bits = 16; + unsigned int frames; + unsigned int period_size = 1024; + unsigned int period_count = 4; + enum pcm_format format; + int no_header = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s {file.wav | --} [-D card] [-d device] [-c channels] " + "[-t seconds] [-r rate] [-b bits] [-p period_size] [-n n_periods]\n\n" + "Use -- for filename to send raw PCM to stdout\n", argv[0]); + return 1; + } + + if (strcmp(argv[1],"--") == 0) { + file = stdout; + prinfo = 0; + no_header = 1; + } else { + file = fopen(argv[1], "wb"); + if (!file) { + fprintf(stderr, "Unable to create file '%s'\n", argv[1]); + return 1; + } + } + + /* parse command line arguments */ + argv += 2; + while (*argv) { + if (strcmp(*argv, "-d") == 0) { + argv++; + if (*argv) + device = atoi(*argv); + } else if (strcmp(*argv, "-c") == 0) { + argv++; + if (*argv) + channels = atoi(*argv); + } else if (strcmp(*argv, "-r") == 0) { + argv++; + if (*argv) + rate = atoi(*argv); + } else if (strcmp(*argv, "-b") == 0) { + argv++; + if (*argv) + bits = atoi(*argv); + } else if (strcmp(*argv, "-D") == 0) { + argv++; + if (*argv) + card = atoi(*argv); + } else if (strcmp(*argv, "-p") == 0) { + argv++; + if (*argv) + period_size = atoi(*argv); + } else if (strcmp(*argv, "-n") == 0) { + argv++; + if (*argv) + period_count = atoi(*argv); + } else if (strcmp(*argv, "-t") == 0) { + argv++; + if (*argv) + loop_seconds = atoi(*argv); + } + if (*argv) + argv++; + } + + header.riff_id = ID_RIFF; + header.riff_sz = 0; + header.riff_fmt = ID_WAVE; + header.fmt_id = ID_FMT; + header.fmt_sz = 16; + header.audio_format = FORMAT_PCM; + header.num_channels = channels; + header.sample_rate = rate; + + switch (bits) { + case 32: + format = PCM_FORMAT_S32_LE; + break; + case 24: + format = PCM_FORMAT_S24_LE; + break; + case 16: + format = PCM_FORMAT_S16_LE; + break; + default: + fprintf(stderr, "%d bits is not supported.\n", bits); + return 1; + } + + header.bits_per_sample = pcm_format_to_bits(format); + header.byte_rate = (header.bits_per_sample / 8) * channels * rate; + header.block_align = channels * (header.bits_per_sample / 8); + header.data_id = ID_DATA; + + /* leave enough room for header */ + if (!no_header) { + fseek(file, sizeof(struct wav_header), SEEK_SET); + } + + /* install signal handler and begin capturing */ + signal(SIGINT, sigint_handler); + frames = capture_sample(file, card, device, header.num_channels, + header.sample_rate, format, + period_size, period_count); + if (prinfo) { + printf("Captured %d frames\n", frames); + } + + /* write header now all information is known */ + if (!no_header) { + header.data_sz = frames * header.block_align; + header.riff_sz = header.data_sz + sizeof(header) - 8; + fseek(file, 0, SEEK_SET); + fwrite(&header, sizeof(struct wav_header), 1, file); + } + + fclose(file); + + return 0; +} + +unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, + unsigned int channels, unsigned int rate, + enum pcm_format format, unsigned int period_size, + unsigned int period_count) +{ + struct pcm_config config; + struct pcm *pcm; + struct pcm *pcm1; + char *buffer; + unsigned int size; + unsigned int frames; + unsigned long long bytes_read = 0; + struct timeval tv; + struct timezone tz; + long time_sec1; + long time_sec2; + long time_total; + + config.channels = channels; + config.rate = rate; + config.period_size = period_size; + config.period_count = period_count; + config.format = format; + config.start_threshold = 0; + config.stop_threshold = 0; + config.silence_threshold = 0; + + pcm = pcm_open(card, device, PCM_IN, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device (%s)\n", + pcm_get_error(pcm)); + return 0; + } + + if (device == 0) + pcm1 = pcm_open(2, 0, PCM_IN, &config); + else + printf("error: device is error"); + if (!pcm1 || !pcm_is_ready(pcm1)) { + fprintf(stderr, "Unable to open PCM device %u (%s)\n", + device, pcm_get_error(pcm1)); + return 0; + } + + pcm_prepare(pcm); + pcm_prepare(pcm1); + + size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + pcm_close(pcm1); + return 0; + } + + if (prinfo) { + printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, + pcm_format_to_bits(format)); + } + + gettimeofday(&tv, &tz); + time_sec1 = tv.tv_sec; + while (capturing && !pcm_read(pcm, buffer, size)) { + if (fwrite(buffer, 1, size, file) != size) { + fprintf(stderr,"Error capturing sample\n"); + break; + } + gettimeofday(&tv, &tz); + time_sec2 = tv.tv_sec; + time_total = time_sec2 - time_sec1; + if (time_total >= (loop_seconds)) { + printf("time_total:%ld, loop_seconds:%d\n", + time_total, loop_seconds); + break; + } + bytes_read += size; + } + frames = pcm_bytes_to_frames(pcm, bytes_read); + free(buffer); + pcm_close(pcm); + pcm_close(pcm1); + return frames; +} + diff --git a/external/cache/sources/tinyalsa_hub/tinymix.c b/external/cache/sources/tinyalsa_hub/tinymix.c new file mode 100644 index 000000000000..fa3defc39090 --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/tinymix.c @@ -0,0 +1,317 @@ +/* tinymix.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 +#include +#include +#include +#include +#include +#include +#include + +static void tinymix_list_controls(struct mixer *mixer); +static void tinymix_detail_control(struct mixer *mixer, const char *control, + int print_all); +static void tinymix_set_value(struct mixer *mixer, const char *control, + char **values, unsigned int num_values); +static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all); + +int main(int argc, char **argv) +{ + struct mixer *mixer; + int card = 0; + + if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) { + argv++; + if (argv[1]) { + card = atoi(argv[1]); + argv++; + argc -= 2; + } else { + argc -= 1; + } + } + + mixer = mixer_open(card); + if (!mixer) { + fprintf(stderr, "Failed to open mixer\n"); + return EXIT_FAILURE; + } + + + if (argc == 1) { + printf("Mixer name: '%s'\n", mixer_get_name(mixer)); + tinymix_list_controls(mixer); + } else if (argc == 2) { + tinymix_detail_control(mixer, argv[1], 1); + } else if (argc >= 3) { + tinymix_set_value(mixer, argv[1], &argv[2], argc - 2); + } else { + printf("Usage: tinymix [-D card] [control id] [value to set]\n"); + } + + mixer_close(mixer); + + return 0; +} + +static void tinymix_list_controls(struct mixer *mixer) +{ + struct mixer_ctl *ctl; + const char *name, *type; + unsigned int num_ctls, num_values; + unsigned int i; + + num_ctls = mixer_get_num_ctls(mixer); + + printf("Number of controls: %d\n", num_ctls); + + printf("ctl\ttype\tnum\t%-40s value\n", "name"); + for (i = 0; i < num_ctls; i++) { + ctl = mixer_get_ctl(mixer, i); + + name = mixer_ctl_get_name(ctl); + type = mixer_ctl_get_type_string(ctl); + num_values = mixer_ctl_get_num_values(ctl); + printf("%d\t%s\t%d\t%-40s", i, type, num_values, name); + tinymix_detail_control(mixer, name, 0); + } +} + +static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all) +{ + unsigned int num_enums; + unsigned int i; + const char *string; + + num_enums = mixer_ctl_get_num_enums(ctl); + + for (i = 0; i < num_enums; i++) { + string = mixer_ctl_get_enum_string(ctl, i); + if (print_all) + printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "", + string); + else if (mixer_ctl_get_value(ctl, 0) == (int)i) + printf(" %-s", string); + } +} + +static void tinymix_detail_control(struct mixer *mixer, const char *control, + int print_all) +{ + struct mixer_ctl *ctl; + enum mixer_ctl_type type; + unsigned int num_values; + unsigned int i; + int min, max; + int ret; + char buf[512] = { 0 }; + size_t len; + + if (isdigit(control[0])) + ctl = mixer_get_ctl(mixer, atoi(control)); + else + ctl = mixer_get_ctl_by_name(mixer, control); + + if (!ctl) { + fprintf(stderr, "Invalid mixer control\n"); + return; + } + + type = mixer_ctl_get_type(ctl); + num_values = mixer_ctl_get_num_values(ctl); + + if (type == MIXER_CTL_TYPE_BYTE) { + len = num_values; + if (len > sizeof(buf)) { + fprintf(stderr, "Truncating get to %zu bytes\n", sizeof(buf)); + len = sizeof(buf); + } + ret = mixer_ctl_get_array(ctl, buf, len); + if (ret < 0) { + fprintf(stderr, "Failed to mixer_ctl_get_array\n"); + return; + } + } + + if (print_all) + printf("%s:", mixer_ctl_get_name(ctl)); + + for (i = 0; i < num_values; i++) { + switch (type) + { + case MIXER_CTL_TYPE_INT: + printf(" %d", mixer_ctl_get_value(ctl, i)); + break; + case MIXER_CTL_TYPE_BOOL: + printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off"); + break; + case MIXER_CTL_TYPE_ENUM: + tinymix_print_enum(ctl, print_all); + break; + case MIXER_CTL_TYPE_BYTE: + printf("%02x", buf[i]); + break; + default: + printf(" unknown"); + break; + }; + } + + if (print_all) { + if (type == MIXER_CTL_TYPE_INT) { + min = mixer_ctl_get_range_min(ctl); + max = mixer_ctl_get_range_max(ctl); + printf(" (range %d->%d)", min, max); + } + } + printf("\n"); +} + +static void tinymix_set_byte_ctl(struct mixer_ctl *ctl, const char *control, + char **values, unsigned int num_values) +{ + int ret; + char buf[512] = { 0 }; + char *end; + int i; + long n; + + if (num_values > sizeof(buf)) { + fprintf(stderr, "Truncating set to %zu bytes\n", sizeof(buf)); + num_values = sizeof(buf); + } + + for (i = 0; i < num_values; i++) { + errno = 0; + n = strtol(values[i], &end, 0); + if (*end) { + fprintf(stderr, "%s not an integer\n", values[i]); + exit(EXIT_FAILURE); + } + if (errno) { + fprintf(stderr, "strtol: %s: %s\n", values[i], + strerror(errno)); + exit(EXIT_FAILURE); + } + if (n < 0 || n > 0xff) { + fprintf(stderr, "%s should be between [0, 0xff]\n", + values[i]); + exit(EXIT_FAILURE); + } + buf[i] = n; + } + + ret = mixer_ctl_set_array(ctl, buf, num_values); + if (ret < 0) { + fprintf(stderr, "Failed to set binary control\n"); + exit(EXIT_FAILURE); + } +} + +static int is_int(char *value) +{ + char* end; + long int result; + + errno = 0; + result = strtol(value, &end, 10); + + if (result == LONG_MIN || result == LONG_MAX) + return 0; + + return errno == 0 && *end == '\0'; +} + +static void tinymix_set_value(struct mixer *mixer, const char *control, + char **values, unsigned int num_values) +{ + struct mixer_ctl *ctl; + enum mixer_ctl_type type; + unsigned int num_ctl_values; + unsigned int i; + + if (isdigit(control[0])) + ctl = mixer_get_ctl(mixer, atoi(control)); + else + ctl = mixer_get_ctl_by_name(mixer, control); + + if (!ctl) { + fprintf(stderr, "Invalid mixer control\n"); + return; + } + + type = mixer_ctl_get_type(ctl); + num_ctl_values = mixer_ctl_get_num_values(ctl); + + if (type == MIXER_CTL_TYPE_BYTE) { + tinymix_set_byte_ctl(ctl, control, values, num_values); + return; + } + + if (is_int(values[0])) { + if (num_values == 1) { + /* Set all values the same */ + int value = atoi(values[0]); + + for (i = 0; i < num_ctl_values; i++) { + if (mixer_ctl_set_value(ctl, i, value)) { + fprintf(stderr, "Error: invalid value\n"); + return; + } + } + } else { + /* Set multiple values */ + if (num_values > num_ctl_values) { + fprintf(stderr, + "Error: %d values given, but control only takes %d\n", + num_values, num_ctl_values); + return; + } + for (i = 0; i < num_values; i++) { + if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) { + fprintf(stderr, "Error: invalid value for index %d\n", i); + return; + } + } + } + } else { + if (type == MIXER_CTL_TYPE_ENUM) { + if (num_values != 1) { + fprintf(stderr, "Enclose strings in quotes and try again\n"); + return; + } + if (mixer_ctl_set_enum_by_string(ctl, values[0])) + fprintf(stderr, "Error: invalid enum value\n"); + } else { + fprintf(stderr, "Error: only enum types can be set with strings\n"); + } + } +} + diff --git a/external/cache/sources/tinyalsa_hub/tinypcminfo.c b/external/cache/sources/tinyalsa_hub/tinypcminfo.c new file mode 100644 index 000000000000..40912aab4e9b --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/tinypcminfo.c @@ -0,0 +1,203 @@ +/* tinypcminfo.c +** +** Copyright 2012, 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 +#include +#include +#include + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +#endif + +/* The format_lookup is in order of SNDRV_PCM_FORMAT_##index and + * matches the grouping in sound/asound.h. Note this is not + * continuous and has an empty gap from (25 - 30). + */ +static const char *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", + [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 +}; + +/* Returns a human readable name for the format associated with bit_index, + * NULL if bit_index is not known. + */ +char *pcm_get_format_name(unsigned bit_index) +{ + return bit_index < ARRAY_SIZE(format_lookup) ? format_lookup[bit_index] : NULL; +} + +int main(int argc, char **argv) +{ + unsigned int device = 0; + unsigned int card = 0; + int i; + + if (argc < 3) { + fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]); + return 1; + } + + /* parse command line arguments */ + argv += 1; + while (*argv) { + if (strcmp(*argv, "-D") == 0) { + argv++; + if (*argv) + card = atoi(*argv); + } + if (strcmp(*argv, "-d") == 0) { + argv++; + if (*argv) + device = atoi(*argv); + } + if (*argv) + argv++; + } + + printf("Info for card %d, device %d:\n", card, device); + + for (i = 0; i < 2; i++) { + struct pcm_params *params; + struct pcm_mask *m; + unsigned int min; + unsigned int max; + + printf("\nPCM %s:\n", i == 0 ? "out" : "in"); + + params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN); + if (params == NULL) { + printf("Device does not exist.\n"); + continue; + } + + m = pcm_params_get_mask(params, PCM_PARAM_ACCESS); + if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */ + printf(" Access:\t%#08x\n", m->bits[0]); + } + m = pcm_params_get_mask(params, PCM_PARAM_FORMAT); + if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */ + unsigned j, k, count = 0; + const unsigned bitcount = sizeof(m->bits[0]) * 8; + + /* we only check first two format masks (out of 8) - others are zero. */ + printf(" Format[0]:\t%#08x\n", m->bits[0]); + printf(" Format[1]:\t%#08x\n", m->bits[1]); + + /* print friendly format names, if they exist */ + for (k = 0; k < 2; ++k) { + for (j = 0; j < bitcount; ++j) { + const char *name; + + if (m->bits[k] & (1 << j)) { + name = pcm_get_format_name(j + k*bitcount); + if (name) { + if (count++ == 0) { + printf(" Format Name:\t"); + } else { + printf (", "); + } + printf("%s", name); + } + } + } + } + if (count) { + printf("\n"); + } + } + m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT); + if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */ + printf(" Subformat:\t%#08x\n", m->bits[0]); + } + min = pcm_params_get_min(params, PCM_PARAM_RATE); + max = pcm_params_get_max(params, PCM_PARAM_RATE); + printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max); + min = pcm_params_get_min(params, PCM_PARAM_CHANNELS); + max = pcm_params_get_max(params, PCM_PARAM_CHANNELS); + printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max); + min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS); + max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS); + printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max); + min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE); + max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE); + printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max); + min = pcm_params_get_min(params, PCM_PARAM_PERIODS); + max = pcm_params_get_max(params, PCM_PARAM_PERIODS); + printf("Period count:\tmin=%u\t\tmax=%u\n", min, max); + + pcm_params_free(params); + } + + return 0; +} diff --git a/external/cache/sources/tinyalsa_hub/tinyplay_hub.c b/external/cache/sources/tinyalsa_hub/tinyplay_hub.c new file mode 100644 index 000000000000..fd59527e5a5b --- /dev/null +++ b/external/cache/sources/tinyalsa_hub/tinyplay_hub.c @@ -0,0 +1,333 @@ +/* tinyplay.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 +#include +#include +#include +#include +#include +#include + +#define ID_RIFF 0x46464952 +#define ID_WAVE 0x45564157 +#define ID_FMT 0x20746d66 +#define ID_DATA 0x61746164 + +struct riff_wave_header { + uint32_t riff_id; + uint32_t riff_sz; + uint32_t wave_id; +}; + +struct chunk_header { + uint32_t id; + uint32_t sz; +}; + +struct chunk_fmt { + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; +}; + +static int close = 0; +static unsigned int loop_num = 1; +static unsigned int loop_minutes = 0; + +void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count); + +void stream_close(int sig) +{ + /* allow the stream to be closed gracefully */ + signal(sig, SIG_IGN); + close = 1; +} + +int main(int argc, char **argv) +{ + FILE *file; + struct riff_wave_header riff_wave_header; + struct chunk_header chunk_header; + struct chunk_fmt chunk_fmt; + unsigned int device = 0; + unsigned int card = 0; + unsigned int period_size = 1024; + unsigned int period_count = 4; + char *filename; + int more_chunks = 1; + + if (argc < 2) { + fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] " + "[-m loop_minutes] [-i loop_num] " + "[-p period_size] [-n period_count] \n", argv[0]); + return 1; + } + + filename = argv[1]; + file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "Unable to open file '%s'\n", filename); + return 1; + } + + fread(&riff_wave_header, sizeof(riff_wave_header), 1, file); + if ((riff_wave_header.riff_id != ID_RIFF) || + (riff_wave_header.wave_id != ID_WAVE)) { + fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename); + fclose(file); + return 1; + } + + do { + fread(&chunk_header, sizeof(chunk_header), 1, file); + + switch (chunk_header.id) { + case ID_FMT: + fread(&chunk_fmt, sizeof(chunk_fmt), 1, file); + /* If the format header is larger, skip the rest */ + if (chunk_header.sz > sizeof(chunk_fmt)) + fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR); + break; + case ID_DATA: + /* Stop looking for chunks */ + more_chunks = 0; + break; + default: + /* Unknown chunk, skip bytes */ + fseek(file, chunk_header.sz, SEEK_CUR); + } + } while (more_chunks); + + /* parse command line arguments */ + argv += 2; + while (*argv) { + if (strcmp(*argv, "-d") == 0) { + argv++; + if (*argv) + device = atoi(*argv); + } + if (strcmp(*argv, "-p") == 0) { + argv++; + if (*argv) + period_size = atoi(*argv); + } + if (strcmp(*argv, "-n") == 0) { + argv++; + if (*argv) + period_count = atoi(*argv); + } + if (strcmp(*argv, "-D") == 0) { + argv++; + if (*argv) + card = atoi(*argv); + } + if (strcmp(*argv, "-m") == 0) { + argv++; + if (*argv) + loop_minutes = atoi(*argv); + } + if (strcmp(*argv, "-i") == 0) { + argv++; + if (*argv) + loop_num = atoi(*argv); + } + if (*argv) + argv++; + } + + play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate, + chunk_fmt.bits_per_sample, period_size, period_count); + + fclose(file); + + return 0; +} + +int check_param(struct pcm_params *params, unsigned int param, unsigned int value, + char *param_name, char *param_unit) +{ + unsigned int min; + unsigned int max; + int is_within_bounds = 1; + + min = pcm_params_get_min(params, param); + if (value < min) { + fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value, + param_unit, min, param_unit); + is_within_bounds = 0; + } + + max = pcm_params_get_max(params, param); + if (value > max) { + fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value, + param_unit, max, param_unit); + is_within_bounds = 0; + } + + return is_within_bounds; +} + +int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count) +{ + struct pcm_params *params; + int can_play; + + params = pcm_params_get(card, device, PCM_OUT); + if (params == NULL) { + fprintf(stderr, "Unable to open PCM device %u.\n", device); + return 0; + } + + can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz"); + can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels"); + can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits"); + can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz"); + can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz"); + + pcm_params_free(params); + + return can_play; +} + +void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, + unsigned int rate, unsigned int bits, unsigned int period_size, + unsigned int period_count) +{ + struct pcm_config config; + struct pcm *pcm; + struct pcm *pcm1; + char *buffer; + int size; + int num_read; + struct timeval tv; + struct timezone tz; + long sec_start = 0; + long sec_end = 0; + int loop_count = 0; + + config.channels = channels; + config.rate = rate; + config.period_size = period_size; + config.period_count = period_count; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + else if (bits == 24) + config.format = PCM_FORMAT_S24_LE; + config.start_threshold = 0; + config.stop_threshold = 0; + config.silence_threshold = 0; + + if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) { + return; + } + + pcm = pcm_open(card, device, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device %u (%s)\n", + device, pcm_get_error(pcm)); + return; + } + + if (device == 0) + pcm1 = pcm_open(1, 0, PCM_OUT, &config); + else if (device == 1) + pcm1 = pcm_open(2, 0, PCM_OUT, &config); + else if (device == 2) + pcm1 = pcm_open(4, 0, PCM_OUT, &config); + else + printf("error: device is error"); + if (!pcm1 || !pcm_is_ready(pcm1)) { + fprintf(stderr, "Unable to open PCM device %u (%s)\n", + device, pcm_get_error(pcm1)); + return; + } + + pcm_prepare(pcm); + pcm_prepare(pcm1); + + size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + pcm_close(pcm1); + return; + } + + printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); + + /* catch ctrl-c to shutdown cleanly */ + signal(SIGINT, stream_close); + + gettimeofday(&tv, &tz); + sec_start = tv.tv_sec; + + printf("start --> loop_minutes = %d; loop_num = %d\n", + loop_minutes, loop_num); + + do { + num_read = fread(buffer, 1, size, file); + if (num_read > 0) { + if (pcm_write(pcm, buffer, num_read)) { + fprintf(stderr, "Error playing sample\n"); + break; + } + if (feof(file)) { + printf("--> loop_count = %d\n", ++loop_count); + fseek(file, 0L, SEEK_SET); + } + if (loop_minutes == 0) { + if (loop_count >= loop_num) + break; + } else { + gettimeofday(&tv, &tz); + sec_end = tv.tv_sec; + if ((sec_end - sec_start) > (loop_minutes * 60)) { + printf("End loop_minutes: %ld\n", (sec_end - sec_start)/60); + break; + } + } + } + } while (!close && num_read > 0); + + free(buffer); + pcm_close(pcm); + pcm_close(pcm1); +} +