diff --git a/Makefile b/Makefile index e343d43..72501af 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,15 @@ all: jni/* install: all install -d ipk/airunit/data/opt/etc/preload.d/ - install libs/armeabi-v7a/lib*.so ipk/airunit/data/opt/etc/preload.d/ + install -d ipk/glasses/data/opt/etc/preload.d/ + install libs/armeabi-v7a/liblive_audio_v2_au.so ipk/airunit/data/opt/etc/preload.d/ + install libs/armeabi-v7a/libtinyalsa.so ipk/glasses/data/opt/etc/preload.d/ + install libs/armeabi-v7a/tinyplay_udp ipk/glasses/data/opt/bin/ ipk: all $(MAKE) -C ipk clean $(MAKE) install + chmod +x ipk/glasses/data/opt/bin/tinyplay_udp $(MAKE) -C ipk mv ipk/airunit/*.ipk ./ mv ipk/glasses/*.ipk ./ @@ -17,4 +21,6 @@ clean: rm -f *.ipk rm -rf libs rm -rf obj - rm ipk/airunit/data/opt/etc/preload.d/liblive_audio_v2_au.so \ No newline at end of file + rm ipk/airunit/data/opt/etc/preload.d/liblive_audio_v2_au.so + rm ipk/glasses/data/opt/etc/preload.d/libtinyalsa.so + rm ipk/glasses/data/opt/bin/tinyplay_udp \ No newline at end of file diff --git a/ipk/airunit/control/control b/ipk/airunit/control/control index a1959ee..f5d0c44 100644 --- a/ipk/airunit/control/control +++ b/ipk/airunit/control/control @@ -1,5 +1,5 @@ Package: live-audio-v2-airside -Version: 0.0.4 +Version: 0.0.5 Maintainer: funnel Description: Live audio V2 airside. Homepage: https://github.com/funneld/djifpv_live_audio_V2 diff --git a/ipk/airunit/data/opt/bin/live_audio_v2_airside.sh b/ipk/airunit/data/opt/bin/live_audio_v2_airside.sh index bac3d71..98b4f57 100644 --- a/ipk/airunit/data/opt/bin/live_audio_v2_airside.sh +++ b/ipk/airunit/data/opt/bin/live_audio_v2_airside.sh @@ -5,7 +5,8 @@ if grep -q "WM150" /system/etc/dji.json; then echo "SD card found. Live audio will start only while recording." else echo "No SD card found. Start tinycap." - LD_PRELOAD="/opt/etc/preload.d/liblive_audio_v2_au.so" tinycap /dev/null -r 48000 -b 16 + sleep 3 + LD_PRELOAD="/opt/etc/preload.d/liblive_audio_v2_au.so" tinycap /dev/null -r 48000 -b 16 > /dev/null 2>&1 fi else echo "Airunit not compatible. Exit." diff --git a/ipk/glasses/control/control b/ipk/glasses/control/control index 6b81bdb..3c81f7a 100644 --- a/ipk/glasses/control/control +++ b/ipk/glasses/control/control @@ -1,7 +1,7 @@ Package: live-audio-v2-glasses -Version: 0.0.2 +Version: 0.0.3 Maintainer: funnel Description: Live audio V2. Homepage: https://github.com/funneld/djifpv_live_audio_V2 Architecture: pigeon-glasses -Depends: dinit, ffmpeg +Depends: dinit diff --git a/ipk/glasses/data/opt/bin/live_audio_v2_glasses.sh b/ipk/glasses/data/opt/bin/live_audio_v2_glasses.sh index 9a0bbca..acb8fdf 100644 --- a/ipk/glasses/data/opt/bin/live_audio_v2_glasses.sh +++ b/ipk/glasses/data/opt/bin/live_audio_v2_glasses.sh @@ -1,4 +1,4 @@ #!/system/bin/sh -mkfifo /tmp/audiopipe -ffmpeg -y -probesize 32 -fflags nobuffer -flags low_delay -err_detect aggressive -fflags discardcorrupt -f u16le -ar 48000 -ac 2 -i udp://localhost:45151 -f u16le /tmp/audiopipe | tinyplay /tmp/audiopipe -i raw -d 0 -r 48000 -b 16 -c 2 +sleep 5 +LD_PRELOAD="/opt/etc/preload.d/libtinyalsa.so" /opt/bin/tinyplay_udp > /dev/null 2>&1 diff --git a/jni/Android.mk b/jni/Android.mk index 23e053a..cb1ca10 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -1,12 +1,24 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) - -LOCAL_CFLAGS += -fPIC -std=c99 +LOCAL_CFLAGS += -fPIC -std=c99 -O3 LOCAL_LDFLAGS += -fPIC LOCAL_LDLIBS := -llog - LOCAL_MODULE := live_audio_v2_au LOCAL_SRC_FILES := live_audio_v2_au.c +include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_CFLAGS += -fPIC -std=c99 -O3 +LOCAL_LDFLAGS += -fPIC +LOCAL_SRC_FILES:= tinyalsa/mixer.c tinyalsa/pcm.c +LOCAL_MODULE := libtinyalsa include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_CFLAGS += -fPIC -std=c99 -O3 +LOCAL_LDFLAGS += -fPIC +LOCAL_SRC_FILES:= tinyplay_udp.c +LOCAL_MODULE := tinyplay_udp +LOCAL_SHARED_LIBRARIES:= libtinyalsa +include $(BUILD_EXECUTABLE) \ No newline at end of file diff --git a/jni/tinyalsa/asound.h b/jni/tinyalsa/asound.h new file mode 100644 index 0000000..e5473a5 --- /dev/null +++ b/jni/tinyalsa/asound.h @@ -0,0 +1,839 @@ +/**************************************************************************** + **************************************************************************** + *** + *** 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. + *** + *** To edit the content of this header, modify the corresponding + *** source file (e.g. under external/kernel-headers/original/) then + *** run bionic/libc/kernel/tools/update_all.py + *** + *** Any manual change here will be lost the next time this script will + *** be run. You've been warned! + *** + **************************************************************************** + ****************************************************************************/ +#ifndef _UAPI__SOUND_ASOUND_H +#define _UAPI__SOUND_ASOUND_H +#ifdef __linux__ +#include +#else +#include +#endif +#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]; +}; +struct snd_cea_861_aud_if { + unsigned char db1_ct_cc; + unsigned char db2_sf_ss; + unsigned char db3; + unsigned char db4_ca; + unsigned char db5_dminh_lsv; +}; +#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_FW_DICE, + SNDRV_HWDEP_IFACE_FW_FIREWORKS, + SNDRV_HWDEP_IFACE_FW_BEBOB, + SNDRV_HWDEP_IFACE_FW_OXFW, + SNDRV_HWDEP_IFACE_FW_DIGI00X, + SNDRV_HWDEP_IFACE_FW_TASCAM, + SNDRV_HWDEP_IFACE_LINE6, + SNDRV_HWDEP_IFACE_FW_MOTU, + SNDRV_HWDEP_IFACE_FW_FIREFACE, + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_FIREFACE +}; +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, 14) +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_S20_LE ((__force snd_pcm_format_t) 25) +#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) +#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) +#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) +#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_DSD_U8 ((__force snd_pcm_format_t) 48) +#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) +#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) +#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) +#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE +#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8 +#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 +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_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 +#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE +#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_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_SYNC_APPLPTR 0x00000020 +#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_HAS_WALL_CLOCK 0x01000000 +#define SNDRV_PCM_INFO_HAS_LINK_ATIME 0x01000000 +#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME 0x02000000 +#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME 0x04000000 +#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000 +#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 +#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 int proto; + unsigned int tstamp_type; + unsigned char reserved[56]; +}; +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; + unsigned int first; + unsigned int step; +}; +enum { + SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, + SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +}; +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; + __u32 audio_tstamp_data; + struct timespec audio_tstamp; + struct timespec driver_tstamp; + __u32 audio_tstamp_accuracy; + unsigned char reserved[52 - 2 * sizeof(struct timespec)]; +}; +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 timespec audio_tstamp; +}; +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_MONOTONIC_RAW, + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, +}; +enum { + SNDRV_CHMAP_UNKNOWN = 0, + SNDRV_CHMAP_NA, + SNDRV_CHMAP_MONO, + SNDRV_CHMAP_FL, + SNDRV_CHMAP_FR, + SNDRV_CHMAP_RL, + SNDRV_CHMAP_RR, + SNDRV_CHMAP_FC, + SNDRV_CHMAP_LFE, + SNDRV_CHMAP_SL, + SNDRV_CHMAP_SR, + SNDRV_CHMAP_RC, + SNDRV_CHMAP_FLC, + SNDRV_CHMAP_FRC, + SNDRV_CHMAP_RLC, + SNDRV_CHMAP_RRC, + SNDRV_CHMAP_FLW, + SNDRV_CHMAP_FRW, + SNDRV_CHMAP_FLH, + SNDRV_CHMAP_FCH, + SNDRV_CHMAP_FRH, + SNDRV_CHMAP_TC, + SNDRV_CHMAP_TFL, + SNDRV_CHMAP_TFR, + SNDRV_CHMAP_TFC, + SNDRV_CHMAP_TRL, + SNDRV_CHMAP_TRR, + SNDRV_CHMAP_TRC, + SNDRV_CHMAP_TFLC, + SNDRV_CHMAP_TFRC, + SNDRV_CHMAP_TSL, + SNDRV_CHMAP_TSR, + SNDRV_CHMAP_LLFE, + SNDRV_CHMAP_RLFE, + SNDRV_CHMAP_BC, + SNDRV_CHMAP_BLC, + SNDRV_CHMAP_BRC, + SNDRV_CHMAP_LAST = SNDRV_CHMAP_BRC, +}; +#define SNDRV_CHMAP_POSITION_MASK 0xffff +#define SNDRV_CHMAP_PHASE_INVERSE (0x01 << 16) +#define SNDRV_CHMAP_DRIVER_SPEC (0x02 << 16) +#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_USER_PVERSION _IOW('A', 0x04, 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_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) +#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, 7) +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) +#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 +struct snd_ctl_elem_id { + unsigned int numid; + snd_ctl_elem_iface_t iface; + unsigned int device; + unsigned int subdevice; + unsigned char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + 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]; + __u64 names_ptr; + unsigned int names_length; + } 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/jni/tinyalsa/asoundlib.h b/jni/tinyalsa/asoundlib.h new file mode 100644 index 0000000..2e8c3e0 --- /dev/null +++ b/jni/tinyalsa/asoundlib.h @@ -0,0 +1,172 @@ +/* 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 + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * PCM API + */ + +struct pcm; + +#define PCM_OUT 0x00000000 +#define PCM_IN 0x10000000 + +/* Bit formats */ +enum pcm_format { + PCM_FORMAT_S16_LE = 0, + PCM_FORMAT_S32_LE, + + PCM_FORMAT_MAX, +}; + +/* 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; +}; + +/* 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); + +/* Set and get config */ +int pcm_get_config(struct pcm *pcm, struct pcm_config *config); +int pcm_set_config(struct pcm *pcm, struct pcm_config *config); + +/* Returns a human readable reason for the last error */ +const char *pcm_get_error(struct pcm *pcm); + +/* Returns the buffer size (int bytes) that should be used for pcm_write. + * This will be 1/2 of the actual fifo size. + */ +unsigned int pcm_get_buffer_size(struct pcm *pcm); + +/* Returns the pcm latency in ms */ +unsigned int pcm_get_latency(struct pcm *pcm); + +/* Returns available frames in pcm buffer and corresponding time stamp. + * 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, void *data, unsigned int count); +int pcm_read(struct pcm *pcm, void *data, unsigned int count); + +/* Start and stop a PCM channel that doesn't transfer data */ +int pcm_start(struct pcm *pcm); +int pcm_stop(struct pcm *pcm); + + +/* + * 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); + +/* 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 */ +int mixer_ctl_get_name(struct mixer_ctl *ctl, char *name, unsigned int size); +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); +int mixer_ctl_get_enum_string(struct mixer_ctl *ctl, unsigned int enum_id, + char *string, unsigned int size); + +/* 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_set_value(struct mixer_ctl *ctl, unsigned int id, int value); +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/jni/tinyalsa/mixer.c b/jni/tinyalsa/mixer.c new file mode 100644 index 0000000..6e98572 --- /dev/null +++ b/jni/tinyalsa/mixer.c @@ -0,0 +1,436 @@ +/* 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 +#define __force +#define __bitwise +#define __user +#include "asound.h" + +#include "asoundlib.h" + +struct mixer_ctl { + struct mixer *mixer; + struct snd_ctl_elem_info *info; + char **ename; +}; + +struct mixer { + int fd; + struct snd_ctl_elem_info *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->info) + free(mixer->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->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); + if (!mixer->ctl || !mixer->info) + 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->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; +} + +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->info[n].id.name)) + return mixer->ctl + n; + + return NULL; +} + +int mixer_ctl_get_name(struct mixer_ctl *ctl, char *name, unsigned int size) +{ + if (!ctl || !name || (size == 0)) + return -EINVAL; + + strncpy(name, (char *)ctl->info->id.name, size); + return 0; +} + +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) +{ + int range; + + if (percent > 100) + percent = 100; + else if (percent < 0) + percent = 0; + + 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]; + + default: + return -EINVAL; + } + + 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: + ev.value.integer.value[id] = value; + break; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + ev.value.enumerated.item[id] = value; + break; + + default: + return -EINVAL; + } + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_get_range_min(struct mixer_ctl *ctl) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + 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; + + return ctl->info->value.integer.min; +} + +int mixer_ctl_get_range_max(struct mixer_ctl *ctl) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + 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; + + 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; +} + +int mixer_ctl_get_enum_string(struct mixer_ctl *ctl, unsigned int enum_id, + char *string, unsigned int size) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) || + (enum_id >= ctl->info->value.enumerated.items)) + 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; + strncpy(string, (char *)ctl->ename[enum_id], size); + + return 0; +} + +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/jni/tinyalsa/pcm.c b/jni/tinyalsa/pcm.c new file mode 100644 index 0000000..2ad67f2 --- /dev/null +++ b/jni/tinyalsa/pcm.c @@ -0,0 +1,489 @@ +/* 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 +#define __force +#define __bitwise +#define __user +#include "asound.h" + +#include "asoundlib.h" + +#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline int param_is_interval(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) && + (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL); +} + +static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n) +{ + return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned 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 void param_set_max(struct snd_pcm_hw_params *p, int n, unsigned int val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->max = val; + } +} + +static 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 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; + } +} + +#define PCM_ERROR_MAX 128 + +struct pcm { + int fd; + unsigned int flags; + int running:1; + int underruns; + unsigned int buffer_size; + 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; +}; + +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; + default: + case PCM_FORMAT_S16_LE: + return SNDRV_PCM_FORMAT_S16_LE; + }; +} + +static unsigned int pcm_format_to_bits(enum pcm_format format) +{ + switch (format) { + case PCM_FORMAT_S32_LE: + return 32; + default: + case PCM_FORMAT_S16_LE: + return 16; + }; +} + +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; +} + +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; + + *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, 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 (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) + return oops(pcm, errno, "cannot write initial data"); + pcm->running = 1; + return 0; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot write stream data"); + } + return 0; + } +} + +int pcm_read(struct pcm *pcm, void *data, unsigned 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 (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) + return oops(pcm, errno, "cannot start channel"); + pcm->running = 1; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot read stream data"); + } + return 0; + } +} + +static struct pcm bad_pcm = { + .fd = -1, +}; + +int pcm_close(struct pcm *pcm) +{ + if (pcm == &bad_pcm) + return 0; + + pcm_hw_munmap_status(pcm); + + if (pcm->fd >= 0) + close(pcm->fd); + 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; + } + + param_init(¶ms); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_RW_INTERLEAVED); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, + pcm_format_to_alsa(config->format)); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); + 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 (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { + oops(pcm, errno, "cannot set hw params"); + goto fail; + } + + memset(&sparams, 0, sizeof(sparams)); + sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; + sparams.period_step = 1; + sparams.avail_min = 1; + + if (!config->start_threshold) + sparams.start_threshold = config->period_count * config->period_size; + else + sparams.start_threshold = config->start_threshold; + + if (!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; + + + 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; + } + + pcm->buffer_size = config->period_count * config->period_size; + pcm->underruns = 0; + return pcm; + +fail: + close(pcm->fd); + pcm->fd = -1; + return pcm; +} + +int pcm_is_ready(struct pcm *pcm) +{ + return pcm->fd >= 0; +} + +int pcm_start(struct pcm *pcm) +{ + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) + return oops(pcm, errno, "cannot start channel"); + + return 0; +} + +int pcm_stop(struct pcm *pcm) +{ + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) + return oops(pcm, errno, "cannot stop channel"); + + return 0; +} + diff --git a/jni/tinyalsa/tinycap.c b/jni/tinyalsa/tinycap.c new file mode 100644 index 0000000..b146309 --- /dev/null +++ b/jni/tinyalsa/tinycap.c @@ -0,0 +1,191 @@ +/* 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 "asoundlib.h" +#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 capturing = 1; + +unsigned int capture_sample(FILE *file, unsigned int device, + unsigned int channels, unsigned int rate, + unsigned int bits); + +void sigint_handler(int sig) +{ + capturing = 0; +} + +int main(int argc, char **argv) +{ + FILE *file; + struct wav_header header; + unsigned int device = 0; + unsigned int channels = 2; + unsigned int rate = 44100; + unsigned int bits = 16; + unsigned int frames; + + if (argc < 2) { + fprintf(stderr, "Usage: %s file.wav [-d device] [-c channels] " + "[-r rate] [-b bits]\n", argv[0]); + return 1; + } + + 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++; + device = atoi(*argv); + } else if (strcmp(*argv, "-c") == 0) { + argv++; + channels = atoi(*argv); + } else if (strcmp(*argv, "-r") == 0) { + argv++; + rate = atoi(*argv); + } else if (strcmp(*argv, "-b") == 0) { + argv++; + bits = atoi(*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; + header.byte_rate = (header.bits_per_sample / 8) * channels * rate; + header.block_align = channels * (header.bits_per_sample / 8); + header.bits_per_sample = bits; + header.data_id = ID_DATA; + + /* leave enough room for header */ + fseek(file, sizeof(struct wav_header), SEEK_SET); + + /* install signal handler and begin capturing */ + signal(SIGINT, sigint_handler); + frames = capture_sample(file, device, header.num_channels, + header.sample_rate, header.bits_per_sample); + printf("Captured %d frames\n", frames); + + /* write header now all information is known */ + header.data_sz = frames * header.block_align; + 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 device, + unsigned int channels, unsigned int rate, + unsigned int bits) +{ + struct pcm_config config; + struct pcm *pcm; + char *buffer; + unsigned int size; + unsigned int bytes_read = 0; + + config.channels = channels; + config.rate = rate; + config.period_size = 1024; + config.period_count = 4; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(0, 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; + } + + size = pcm_get_buffer_size(pcm); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + return 0; + } + + printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); + + while (capturing && !pcm_read(pcm, buffer, size)) { + if (fwrite(buffer, 1, size, file) != size) { + fprintf(stderr,"Error capturing sample\n"); + break; + } + bytes_read += size; + } + + free(buffer); + pcm_close(pcm); + return bytes_read / ((bits / 8) * channels); +} + diff --git a/jni/tinyalsa/tinymix.c b/jni/tinyalsa/tinymix.c new file mode 100644 index 0000000..a9e7b02 --- /dev/null +++ b/jni/tinyalsa/tinymix.c @@ -0,0 +1,178 @@ +/* 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 "asoundlib.h" +#include +#include +#include + +static void tinymix_list_controls(struct mixer *mixer); +static void tinymix_detail_control(struct mixer *mixer, unsigned int id); +static void tinymix_set_value(struct mixer *mixer, unsigned int id, + char *value); + +int main(int argc, char **argv) +{ + struct mixer *mixer; + + mixer = mixer_open(0); + if (!mixer) { + fprintf(stderr, "Failed to open mixer\n"); + return EXIT_FAILURE; + } + + if (argc == 1) + tinymix_list_controls(mixer); + else if (argc == 2) + tinymix_detail_control(mixer, atoi(argv[1])); + else if (argc == 3) + tinymix_set_value(mixer, atoi(argv[1]), argv[2]); + else + printf("Usage: tinymix [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 *type; + unsigned int num_ctls, num_values; + char buffer[256]; + unsigned int i; + + num_ctls = mixer_get_num_ctls(mixer); + + printf("Number of controls: %d\n", num_ctls); + + printf("ctl\ttype\tnum\tname\n"); + for (i = 0; i < num_ctls; i++) { + ctl = mixer_get_ctl(mixer, i); + + mixer_ctl_get_name(ctl, buffer, sizeof(buffer)); + type = mixer_ctl_get_type_string(ctl); + num_values = mixer_ctl_get_num_values(ctl); + + printf("%d\t%s\t%d\t%s\n", i, type, num_values, buffer); + } +} + +static void tinymix_print_enum(struct mixer_ctl *ctl) +{ + unsigned int num_enums; + char buffer[256]; + unsigned int i; + + num_enums = mixer_ctl_get_num_enums(ctl); + + for (i = 0; i < num_enums; i++) { + mixer_ctl_get_enum_string(ctl, i, buffer, sizeof(buffer)); + printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "", + buffer); + } +} + +static void tinymix_detail_control(struct mixer *mixer, unsigned int id) +{ + struct mixer_ctl *ctl; + enum mixer_ctl_type type; + unsigned int num_values; + char buffer[256]; + unsigned int i; + int min, max; + + if (id >= mixer_get_num_ctls(mixer)) { + fprintf(stderr, "Invalid mixer control\n"); + return; + } + + ctl = mixer_get_ctl(mixer, id); + + mixer_ctl_get_name(ctl, buffer, sizeof(buffer)); + type = mixer_ctl_get_type(ctl); + num_values = mixer_ctl_get_num_values(ctl); + + printf("%s:", buffer); + 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); + break; + default: + printf(" unknown"); + break; + }; + } + 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_value(struct mixer *mixer, unsigned int id, + char *string) +{ + struct mixer_ctl *ctl; + enum mixer_ctl_type type; + unsigned int num_values; + unsigned int i; + + ctl = mixer_get_ctl(mixer, id); + type = mixer_ctl_get_type(ctl); + num_values = mixer_ctl_get_num_values(ctl); + + if (isdigit(string[0])) { + int value = atoi(string); + + for (i = 0; i < num_values; i++) { + if (mixer_ctl_set_value(ctl, i, value)) { + fprintf(stderr, "Error: invalid value\n"); + return; + } + } + } else { + if (type == MIXER_CTL_TYPE_ENUM) { + if (mixer_ctl_set_enum_by_string(ctl, string)) + fprintf(stderr, "Error: invalid enum value\n"); + } else { + fprintf(stderr, "Error: only enum types can be set with strings\n"); + } + } +} + diff --git a/jni/tinyalsa/tinyplay.c b/jni/tinyalsa/tinyplay.c new file mode 100644 index 0000000..a01182a --- /dev/null +++ b/jni/tinyalsa/tinyplay.c @@ -0,0 +1,145 @@ +/* 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 "asoundlib.h" +#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; +}; + +void play_sample(FILE *file, unsigned int channels, unsigned int rate, + unsigned int bits); + +int main(int argc, char **argv) +{ + FILE *file; + struct wav_header header; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + file = fopen(argv[1], "rb"); + if (!file) { + fprintf(stderr, "Unable to open file '%s'\n", argv[1]); + return 1; + } + + fread(&header, sizeof(struct wav_header), 1, file); + + if ((header.riff_id != ID_RIFF) || + (header.riff_fmt != ID_WAVE) || + (header.fmt_id != ID_FMT) || + (header.audio_format != FORMAT_PCM) || + (header.fmt_sz != 16)) { + fprintf(stderr, "Error: '%s' is not a PCM riff/wave file\n", argv[1]); + fclose(file); + return 1; + } + + play_sample(file, header.num_channels, header.sample_rate, + header.bits_per_sample); + + fclose(file); + + return 0; +} + +void play_sample(FILE *file, unsigned int channels, unsigned int rate, + unsigned int bits) +{ + struct pcm_config config; + struct pcm *pcm; + char *buffer; + int size; + int num_read; + + config.channels = channels; + config.rate = 48000; + config.period_size = 1024; + config.period_count = 4; + if (bits == 32) + config.format = PCM_FORMAT_S32_LE; + else if (bits == 16) + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(0, 0, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device (%s)\n", + pcm_get_error(pcm)); + return; + } + + size = pcm_get_buffer_size(pcm); + buffer = malloc(size); + if (!buffer) { + fprintf(stderr, "Unable to allocate %d bytes\n", size); + free(buffer); + pcm_close(pcm); + return; + } + + printf("Playing sample: %u ch, %u hz, %u bit\n", channels, 48000, bits); + + 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; + } + } + } while (num_read > 0); + + free(buffer); + pcm_close(pcm); +} + diff --git a/jni/tinyplay_udp.c b/jni/tinyplay_udp.c new file mode 100644 index 0000000..ed29ef0 --- /dev/null +++ b/jni/tinyplay_udp.c @@ -0,0 +1,112 @@ +/* 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 "tinyalsa/asoundlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 45151 +#define BUFSIZE 4096 + +void play(); +void create_socket(); + +int sockfd; +struct sockaddr_in servaddr, cliaddr; +socklen_t len; + +int main(int argc, char **argv) { + + create_socket(); + play(); + + return 0; +} + +void play() { + + struct pcm_config config; + struct pcm *pcm; + int num_read; + char buf[BUFSIZE]; + + config.channels = 2; + config.rate = 48000; + config.period_size = 1024; + config.period_count = 4; + config.format = PCM_FORMAT_S16_LE; + + pcm = pcm_open(0, 0, PCM_OUT, &config); + if (!pcm || !pcm_is_ready(pcm)) { + fprintf(stderr, "Unable to open PCM device (%s)\n", + pcm_get_error(pcm)); + return; + } + + printf("Playing: %u ch, %u hz, %u bit\n", config.channels, config.rate, 16); + + while (1) { + + if ((num_read = recvfrom(sockfd, buf, BUFSIZE, MSG_WAITALL, (struct sockaddr *) &cliaddr, &len)) < 0) { + perror("recvfrom error"); + exit(EXIT_FAILURE); + } + + pcm_write(pcm, buf, num_read); + } + + pcm_close(pcm); +} + +void create_socket() { + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket error"); + exit(EXIT_FAILURE); + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(PORT); + + if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { + perror("bind error"); + exit(EXIT_FAILURE); + } + + len = sizeof(cliaddr); +}