diff options
Diffstat (limited to 'lib/libsalsa')
-rw-r--r-- | lib/libsalsa/.config | 2 | ||||
-rw-r--r-- | lib/libsalsa/.nativemake | 0 | ||||
-rw-r--r-- | lib/libsalsa/Makefile | 60 | ||||
-rw-r--r-- | lib/libsalsa/README | 34 | ||||
-rw-r--r-- | lib/libsalsa/Versions | 162 | ||||
-rw-r--r-- | lib/libsalsa/alsa-symbols.h | 66 | ||||
-rw-r--r-- | lib/libsalsa/alsakernel.h | 108 | ||||
-rw-r--r-- | lib/libsalsa/local.h | 98 | ||||
-rw-r--r-- | lib/libsalsa/main.c | 498 | ||||
-rw-r--r-- | lib/libsalsa/misc.c | 107 | ||||
-rw-r--r-- | lib/libsalsa/mix.c | 1125 | ||||
-rw-r--r-- | lib/libsalsa/output.c | 411 | ||||
-rw-r--r-- | lib/libsalsa/pcm.c | 3114 | ||||
-rw-r--r-- | lib/libsalsa/rawmidi.c | 236 | ||||
-rw-r--r-- | lib/libsalsa/seq.c | 2230 | ||||
-rw-r--r-- | lib/libsalsa/seq_input.c | 136 | ||||
-rw-r--r-- | lib/libsalsa/seq_output.c | 315 | ||||
-rw-r--r-- | lib/libsalsa/seqmid.c | 205 | ||||
-rw-r--r-- | lib/libsalsa/stubs.c | 59 | ||||
-rw-r--r-- | lib/libsalsa/timer.c | 361 |
20 files changed, 9327 insertions, 0 deletions
diff --git a/lib/libsalsa/.config b/lib/libsalsa/.config new file mode 100644 index 0000000..4094239 --- /dev/null +++ b/lib/libsalsa/.config @@ -0,0 +1,2 @@ +targetos=Linux +depends=ALSA diff --git a/lib/libsalsa/.nativemake b/lib/libsalsa/.nativemake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/libsalsa/.nativemake diff --git a/lib/libsalsa/Makefile b/lib/libsalsa/Makefile new file mode 100644 index 0000000..5f8216b --- /dev/null +++ b/lib/libsalsa/Makefile @@ -0,0 +1,60 @@ +LOBJECTS=main.lo output.lo misc.lo pcm.lo mix.lo seq.lo seqmid.lo rawmidi.lo seq_output.lo timer.lo stubs.lo seq_input.lo + +OSSLIBDIR=/usr/lib/oss + +CFLAGS=-O -I../../include -I../libOSSlib +LIBTOOL=libtool --tag=CC + +all: libsalsa.la + +*.lo: local.h + +main.lo: main.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c main.c + +pcm.lo: pcm.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c pcm.c + +misc.lo: misc.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c misc.c + +stubs.lo: stubs.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c stubs.c + +mix.lo: mix.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c mix.c + +output.lo: output.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c output.c + +seq.lo: seq.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq.c + +timer.lo: timer.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c timer.c + +seqmid.lo: seqmid.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seqmid.c + +seq_input.lo: seq_input.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq_input.c + +seq_output.lo: seq_output.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c seq_output.c + +rawmidi.lo: rawmidi.c + $(LIBTOOL) --mode=compile ${CC} $(CFLAGS) -c rawmidi.c + +libsalsa.la: $(LOBJECTS) + $(LIBTOOL) --mode=link ${CC} -rpath /usr/lib -Wl,--version-script=Versions -version-info 2:0:0 -o libsalsa.la $(LOBJECTS) -L../libOSSlib -lOSSlib + +install: libsalsa.la + $(LIBTOOL) cp libsalsa.la /usr/lib + (cd /usr/lib;ln -sf libsalsa.so.2.0.0 libasound.so) + (cd /usr/lib;ln -sf libsalsa.so.2.0.0 libasound.so.2) + +dep: + +clean: + rm -f core core.* *.o *.a *.lo *.so *.loT *.la x y z *.s + rm -rf .libs diff --git a/lib/libsalsa/README b/lib/libsalsa/README new file mode 100644 index 0000000..e201b5c --- /dev/null +++ b/lib/libsalsa/README @@ -0,0 +1,34 @@ +SALSA - Simple ALSA emulation library for OSS +============================================= + +The sole purpose of this library is to make certain key ALSA applications +to work with OSS. This is necessary just because some Linux distributions +don't ship utilities like esd or xmss with OSS support compiled in. + +This library has been programmed using brute force methods and it's +not designed to be any programming example. We didn't make any attempt to get +all ALSA applications to work with it. Most applications support the OSS +API directly so there is no need for doing this. + +We do not have any specific plans to develop this library any further. However +some changes will be made occasionally. + +Copying +------- + +The seqmid.c, alsakernel.h, alsa-symbols.h and output.c files have been +copied more or less from stock alsa-lib and they have been copyrighted by the +ALSA team members. All parts of this package are distributed under GNU GPL +version 2.1. + +Installing and compiling the library +------------------------------------ + +The precompiled library is already shipped as a part of the OSS package +for Linux 2.6.x and later kernels so there should be no reason to recompile +it. This library is not applicable under any other operating systems or Linux +versions. + +To compile the library you can execute "make". "make install" will install +the library (libsalsa.so.2.0.0) to /usr/lib and then change the required +libasound.so.* symbolic links to point to it. diff --git a/lib/libsalsa/Versions b/lib/libsalsa/Versions new file mode 100644 index 0000000..c4d3065 --- /dev/null +++ b/lib/libsalsa/Versions @@ -0,0 +1,162 @@ +ALSA_0.9 { + global: + __snd_*; + _snd_*; + snd_*; + local: + *; +}; + +ALSA_0.9.0rc4 { + global: + + snd_pcm_hw_params_get_access; + snd_pcm_hw_params_set_access_first; + snd_pcm_hw_params_set_access_last; + + snd_pcm_hw_params_get_format; + snd_pcm_hw_params_set_format_first; + snd_pcm_hw_params_set_format_last; + + snd_pcm_hw_params_get_subformat; + snd_pcm_hw_params_set_subformat_first; + snd_pcm_hw_params_set_subformat_last; + + snd_pcm_hw_params_get_channels; + snd_pcm_hw_params_get_channels_min; + snd_pcm_hw_params_get_channels_max; + snd_pcm_hw_params_set_channels_near; + snd_pcm_hw_params_set_channels_first; + snd_pcm_hw_params_set_channels_last; + + snd_pcm_hw_params_get_rate; + snd_pcm_hw_params_get_rate_min; + snd_pcm_hw_params_get_rate_max; + snd_pcm_hw_params_set_rate_near; + snd_pcm_hw_params_set_rate_first; + snd_pcm_hw_params_set_rate_last; + + snd_pcm_hw_params_get_period_time; + snd_pcm_hw_params_get_period_time_min; + snd_pcm_hw_params_get_period_time_max; + snd_pcm_hw_params_set_period_time_near; + snd_pcm_hw_params_set_period_time_first; + snd_pcm_hw_params_set_period_time_last; + + snd_pcm_hw_params_get_period_size; + snd_pcm_hw_params_get_period_size_min; + snd_pcm_hw_params_get_period_size_max; + snd_pcm_hw_params_set_period_size_near; + snd_pcm_hw_params_set_period_size_first; + snd_pcm_hw_params_set_period_size_last; + + snd_pcm_hw_params_get_periods; + snd_pcm_hw_params_get_periods_min; + snd_pcm_hw_params_get_periods_max; + snd_pcm_hw_params_set_periods_near; + snd_pcm_hw_params_set_periods_first; + snd_pcm_hw_params_set_periods_last; + + snd_pcm_hw_params_get_buffer_time; + snd_pcm_hw_params_get_buffer_time_min; + snd_pcm_hw_params_get_buffer_time_max; + snd_pcm_hw_params_set_buffer_time_near; + snd_pcm_hw_params_set_buffer_time_first; + snd_pcm_hw_params_set_buffer_time_last; + + snd_pcm_hw_params_get_buffer_size; + snd_pcm_hw_params_get_buffer_size_min; + snd_pcm_hw_params_get_buffer_size_max; + snd_pcm_hw_params_set_buffer_size_near; + snd_pcm_hw_params_set_buffer_size_first; + snd_pcm_hw_params_set_buffer_size_last; + + snd_pcm_hw_params_get_tick_time; + snd_pcm_hw_params_get_tick_time_min; + snd_pcm_hw_params_get_tick_time_max; + snd_pcm_hw_params_set_tick_time_near; + snd_pcm_hw_params_set_tick_time_first; + snd_pcm_hw_params_set_tick_time_last; + +} ALSA_0.9; + +ALSA_0.9.0rc8 { + global: + + snd_pcm_forward; + snd_pcm_status_get_trigger_htstamp; + snd_pcm_status_get_htstamp; + +} ALSA_0.9.0rc4; + +ALSA_0.9.0 { + global: + + snd_pcm_type_name; + snd_timer_query_info; + snd_timer_query_params; + snd_timer_query_status; + snd_timer_params_set_exclusive; + snd_timer_params_get_exclusive; + snd_timer_params_set_filter; + snd_timer_params_get_filter; +} ALSA_0.9.0rc8; + +ALSA_0.9.3 { + global: + + snd_ctl_elem_info_get_dimensions; + snd_ctl_elem_info_get_dimension; +} ALSA_0.9.0; + +ALSA_0.9.5 { + global: + + alsa_lisp; +} ALSA_0.9.3; + +ALSA_0.9.6 { + global: + + snd_hctl_open_ctl; + snd_seq_port_info_get_timestamping; + snd_seq_port_info_get_timestamp_real; + snd_seq_port_info_get_timestamp_queue; + snd_seq_port_info_set_timestamping; + snd_seq_port_info_set_timestamp_real; + snd_seq_port_info_set_timestamp_queue; +} ALSA_0.9.5; + +ALSA_0.9.7 { + global: + + snd_user_file; + snd_hctl_ctl; + sndo_*; + alsa_lisp_*; +} ALSA_0.9.6; + +ALSA_0.9.8 { + global: + + snd_ctl_elem_add; + snd_ctl_elem_replace; + snd_ctl_elem_remove; + snd_hctl_poll_descriptors_revents; +} ALSA_0.9.7; + +ALSA_1.0.4 { + global: + + snd_spcm_init; + snd_spcm_init_duplex; + snd_spcm_init_get_params; +} ALSA_0.9.8; + +ALSA_1.0.5 { + global: + + snd_asoundlib_version; + snd_timer_params_set_early_event; + snd_timer_params_get_early_event; +} ALSA_1.0.4; diff --git a/lib/libsalsa/alsa-symbols.h b/lib/libsalsa/alsa-symbols.h new file mode 100644 index 0000000..692846c --- /dev/null +++ b/lib/libsalsa/alsa-symbols.h @@ -0,0 +1,66 @@ +/* + * ALSA lib - dynamic symbol versions + * Copyright (c) 2002 by Jaroslav Kysela <perex@suse.cz> + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ALSA_SYMBOLS_H +#define __ALSA_SYMBOLS_H + +#if defined(PIC) && defined(VERSIONED_SYMBOLS) /* might be also configurable */ +#define USE_VERSIONED_SYMBOLS +#endif + +#define INTERNAL_CONCAT2_2(Pre, Post) Pre##Post +#define INTERNAL(Name) INTERNAL_CONCAT2_2(__, Name) + +#ifdef __powerpc64__ +# define symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@" #version); \ + __asm__ (".symver ." #real ",." #name "@" #version) +# define default_symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@@" #version); \ + __asm__ (".symver ." #real ",." #name "@@" #version) +#else +# define symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@" #version) +# define default_symbol_version(real, name, version) \ + __asm__ (".symver " #real "," #name "@@" #version) +#endif + +#ifdef USE_VERSIONED_SYMBOLS +#define use_symbol_version(real, name, version) \ + symbol_version(real, name, version) +#define use_default_symbol_version(real, name, version) \ + default_symbol_version(real, name, version) +#else +#define use_symbol_version(real, name, version) /* nothing */ +#ifdef __powerpc64__ +#define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " #name); \ + __asm__ (".weak ." #name); \ + __asm__ (".set " #name "," #real); \ + __asm__ (".set ." #name ",." #real) +#else +#define use_default_symbol_version(real, name, version) \ + __asm__ (".weak " #name); \ + __asm__ (".set " #name "," #real) +#endif +#endif + +#endif /* __ALSA_SYMBOLS_H */ diff --git a/lib/libsalsa/alsakernel.h b/lib/libsalsa/alsakernel.h new file mode 100644 index 0000000..1e1fb52 --- /dev/null +++ b/lib/libsalsa/alsakernel.h @@ -0,0 +1,108 @@ + +enum sndrv_pcm_format +{ + SNDRV_PCM_FORMAT_S8 = 0, + SNDRV_PCM_FORMAT_U8, + SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_S24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_LE, /* low three bytes */ + SNDRV_PCM_FORMAT_U24_BE, /* low three bytes */ + SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT_LE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT_BE, /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_LE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_FLOAT64_BE, /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, /* IEC-958 subframe, Little Endian */ + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, /* IEC-958 subframe, Big Endian */ + SNDRV_PCM_FORMAT_MU_LAW, + SNDRV_PCM_FORMAT_A_LAW, + SNDRV_PCM_FORMAT_IMA_ADPCM, + SNDRV_PCM_FORMAT_MPEG, + SNDRV_PCM_FORMAT_GSM, + SNDRV_PCM_FORMAT_SPECIAL = 31, + SNDRV_PCM_FORMAT_S24_3LE = 32, /* in three bytes */ + SNDRV_PCM_FORMAT_S24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U24_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U20_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_S18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3LE, /* in three bytes */ + SNDRV_PCM_FORMAT_U18_3BE, /* in three bytes */ + SNDRV_PCM_FORMAT_LAST = SNDRV_PCM_FORMAT_U18_3BE, + +#ifdef SNDRV_LITTLE_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_LE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_LE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_LE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_LE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_LE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_LE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_LE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_LE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, +#endif +#ifdef SNDRV_BIG_ENDIAN + SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_BE, + SNDRV_PCM_FORMAT_U16 = SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24 = SNDRV_PCM_FORMAT_S24_BE, + SNDRV_PCM_FORMAT_U24 = SNDRV_PCM_FORMAT_U24_BE, + SNDRV_PCM_FORMAT_S32 = SNDRV_PCM_FORMAT_S32_BE, + SNDRV_PCM_FORMAT_U32 = SNDRV_PCM_FORMAT_U32_BE, + SNDRV_PCM_FORMAT_FLOAT = SNDRV_PCM_FORMAT_FLOAT_BE, + SNDRV_PCM_FORMAT_FLOAT64 = SNDRV_PCM_FORMAT_FLOAT64_BE, + SNDRV_PCM_FORMAT_IEC958_SUBFRAME = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE, +#endif +}; + +#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v +static const char *snd_pcm_format_names[] = { + FORMAT (S8), + FORMAT (U8), + FORMAT (S16_LE), + FORMAT (S16_BE), + FORMAT (U16_LE), + FORMAT (U16_BE), + FORMAT (S24_LE), + FORMAT (S24_BE), + FORMAT (U24_LE), + FORMAT (U24_BE), + FORMAT (S32_LE), + FORMAT (S32_BE), + FORMAT (U32_LE), + FORMAT (U32_BE), + FORMAT (FLOAT_LE), + FORMAT (FLOAT_BE), + FORMAT (FLOAT64_LE), + FORMAT (FLOAT64_BE), + FORMAT (IEC958_SUBFRAME_LE), + FORMAT (IEC958_SUBFRAME_BE), + FORMAT (MU_LAW), + FORMAT (A_LAW), + FORMAT (IMA_ADPCM), + FORMAT (MPEG), + FORMAT (GSM), + FORMAT (SPECIAL), + FORMAT (S24_3LE), + FORMAT (S24_3BE), + FORMAT (U24_3LE), + FORMAT (U24_3BE), + FORMAT (S20_3LE), + FORMAT (S20_3BE), + FORMAT (U20_3LE), + FORMAT (U20_3BE), + FORMAT (S18_3LE), + FORMAT (S18_3BE), + FORMAT (U18_3LE), + FORMAT (U18_3BE), +}; diff --git a/lib/libsalsa/local.h b/lib/libsalsa/local.h new file mode 100644 index 0000000..5c87ebc --- /dev/null +++ b/lib/libsalsa/local.h @@ -0,0 +1,98 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include "alsa-symbols.h" +#include <alsa/asoundlib.h> +#include "../../include/soundcard.h" +#include "alsakernel.h" +#include <sys/poll.h> +#include "../../kernel/framework/include/midiparser.h" + +extern int alib_verbose; +extern int mixer_fd; + +extern char alib_appname[64]; + +extern oss_sysinfo sysinfo; + +#define dbg_printf if (alib_verbose>0)printf +#define dbg_printf0 if (alib_verbose>=0)printf +#define dbg_printf1 if (alib_verbose>=1)printf +#define dbg_printf2 if (alib_verbose>=2)printf +#define dbg_printf3 if (alib_verbose>=3)printf + +extern int alib_initialized; + +extern int init_alib (void); + +#define ALIB_INIT() \ +{ \ + int init_err; \ + if (!alib_initialized) \ + if ((init_err=alib_init())<0) \ + return init_err; \ +} + +struct _snd_pcm_info +{ + oss_audioinfo *ainfo; +}; + + +extern int alib_appcheck (void); + +struct _snd_seq_port_info +{ + oss_longname_t name; + int port; + int capability; + int midi_channels; + int synth_voices; + int midi_voices; + int type; +}; + +struct _snd_seq_client_info +{ + oss_longname_t name; + int client; +}; + +/* Size of the local event buffer */ +#define MAX_EVENTS 128 + +struct _snd_seq +{ + int fd; + int streams; + int nonblock; + int oss_mode; + oss_longname_t name; + midiparser_common_t *parser; + + snd_seq_event_t events[MAX_EVENTS]; + int nevents, nextevent; +}; + +struct _snd_rawmidi_info +{ + int dummy; +}; + +struct _snd_seq_queue_status +{ + int dummy; +}; + +struct _snd_seq_queue_timer +{ + int dummy; +}; + +extern int convert_event (snd_seq_t * seq, snd_seq_event_t * ev); +extern void midiparser_callback (void *context, int category, + unsigned char msg, unsigned char ch, + unsigned char *parms, int len); diff --git a/lib/libsalsa/main.c b/lib/libsalsa/main.c new file mode 100644 index 0000000..34c8c22 --- /dev/null +++ b/lib/libsalsa/main.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * Parts of the code is derived from the alsa-lib package that is + * copyrighted by Jaroslav Kysela and the other ALSA team members. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "local.h" + +int mixer_fd = -1; +int alib_initialized = 0; + +oss_sysinfo sysinfo = { 0 }; +struct _snd_ctl +{ + oss_card_info info; + oss_audioinfo ainfo; +}; + +int alib_verbose = 0; + +int +alib_init (void) +{ + char *p; + char *devmixer; + + if ((devmixer=getenv("OSS_MIXERDEV"))==NULL) + devmixer = "/dev/mixer"; + + if ((p = getenv ("ALIB_DEBUG")) != NULL) + alib_verbose = atoi (p); + + if (mixer_fd == -1) + { + if ((mixer_fd = open (devmixer, O_RDONLY, 0)) == -1) + return -errno; + } + + if (ioctl (mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1) + { + perror ("SNDCTL_SYSINFO"); + return -errno; + } + + return 0; +} + +char alib_appname[64] = "salsa"; + +int +alib_appcheck (void) +{ + /* + * Some programs are known to support OSS at the same time with ALSA. + * Prevent them from using this library accidently. + */ + + static int done = 0; + + if (done) + return 1; + + done = 1; + + typedef struct + { + char *name, *msg, *action; + } prog_t; + + static const prog_t banned_programs[] = { + {"artsd", "Please use 'artsd -a oss' instead.", NULL}, + {"kcontrol", NULL, NULL}, + {"kmid", NULL, NULL}, + {"krec", NULL, NULL}, + {"kplay", NULL, NULL}, + {"kamix", "Please use ossxmix instead", NULL}, + {"qamix", "Please use ossxmix instead", NULL}, + NULL + }; + + static const char *whitelist[] = { + "esd", + "kmix", + "gnome-volume-control", + "artsd", + "xmms", + "alsaplayer", + "aplay", + "alsamixer", + "vkeybd", + NULL + }; + + FILE *f; + char tmp[64], *p, *cmd = tmp; + int i; + static int warned = 0; + + if ((f = fopen ("/proc/self/cmdline", "r")) == NULL) + return 1; + + if (fgets (tmp, sizeof (tmp) - 1, f) == NULL) + { + fclose (f); + return 1; + } + + fclose (f); + + p = cmd; + + while (*p && (*p != ' ' && *p != '\n')) + p++; + *p = 0; + + p = cmd = tmp; + while (*p) + { + if (*p == '/') + cmd = p + 1; + p++; + } + + strcpy (alib_appname, cmd); + + for (i = 0; i < strlen (alib_appname); i++) + if (alib_appname[i] < 'a' || alib_appname[i] > 'z') + if (alib_appname[i] < 'A' || alib_appname[i] > 'Z') + if (alib_appname[i] < '0' || alib_appname[i] > '9') + alib_appname[i] = '_'; + + for (i = 0; banned_programs[i].name != NULL; i++) + if (strcmp (banned_programs[i].name, cmd) == 0) + { + if (alib_verbose != 0) + { + return 1; + } + fprintf (stderr, + "\n\n************** WARNING ***********************\n"); + fprintf (stderr, "This program (%s) should not use ALSA emulation\n", + cmd); + if (banned_programs[i].msg != NULL) + fprintf (stderr, "%s\n", banned_programs[i].msg); + fprintf (stderr, + "**************************************************\n\n"); + + if (banned_programs[i].action != NULL) + { + if (fork () == 0) + { + exit (system (banned_programs[i].action)); + } + while (wait () != -1); + exit (1); + } + return 0; + } + + if (alib_verbose == 0) + { + int ok = 0; + + for (i = 0; !ok && whitelist[i] != NULL; i++) + if (strcmp (cmd, whitelist[i]) == 0) + ok = 1; + + + if (!ok) + return 0; + } + + if (!warned) + { + fprintf (stderr, + "\n\n******************** WARNING *******************************\n"); + fprintf (stderr, + "Warning! %s uses ALSA emulation instead of the native OSS API\n", + cmd); + fprintf (stderr, + "****************************************************************\n\n"); + } + warned = 1; + return 1; +} + +typedef struct _snd_ctl_card_info +{ + oss_card_info *info; +} snd_ctl_card_info_t; + +/** + * \brief Try to determine the next card. + * \param rcard pointer to card number + * \result zero if success, otherwise a negative error code + * + * Tries to determine the next card from given card number. + * If card number is -1, then the first available card is + * returned. If the result card number is -1, no more cards + * are available. + */ +int +snd_card_next (int *rcard) +{ + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + if (*rcard == -1) + *rcard = 0; + else + *rcard = *rcard + 1; + + if (*rcard >= sysinfo.numcards) + { + *rcard = -1; + return 0; + } + + return 0; +} + +/** + * \brief Convert card string to an integer value. + * \param string String containing card identifier + * \return zero if success, otherwise a negative error code + * + * The accepted format is an integer value in ASCII representation + * or the card identifier (the id parameter for sound-card drivers). + */ +int +snd_card_get_index (const char *string) +{ + dbg_printf ("snd_card_get_index(%s)\n", string); + return -EINVAL; +} + +/** + * \brief Get card name from a CTL card info + * \param obj CTL card info + * \return card name + */ +const char * +snd_ctl_card_info_get_name (const snd_ctl_card_info_t * obj) +{ + return obj->info->longname; +} + +/** + * \brief get size of #snd_ctl_card_info_t + * \return size in bytes + */ +size_t +snd_ctl_card_info_sizeof () +{ + return sizeof (snd_ctl_card_info_t); +} + +/** + * \brief Opens a CTL + * \param ctlp Returned CTL handle + * \param name ASCII identifier of the CTL handle + * \param mode Open mode (see #SND_CTL_NONBLOCK, #SND_CTL_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_open (snd_ctl_t ** ctlp, const char *name, int mode) +{ + int num; + snd_ctl_t *ctl; + + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + *ctlp = NULL; + + if (strcmp (name, "default") == 0) + num = 0; + else + { + if (name[0] != 'h' && name[1] != 'w' && name[2] != ':') + return -ENOENT; + + if (sscanf (name + 3, "%d", &num) != 1) + return -ENOENT; + } + + if (num < 0 || num >= sysinfo.numcards) + return -ENXIO; + + + if ((ctl = malloc (sizeof (*ctl))) == NULL) + return -ENOMEM; + + memset (ctl, 0, sizeof (*ctl)); + ctl->info.card = num; + if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ctl->info) == -1) + { + perror ("SNDCTL_CARDINFO"); + fprintf (stderr, "Mixer fd was %d\n", mixer_fd); + return -errno; + } + + *ctlp = ctl; + return 0; +} + +/** + * \brief close CTL handle + * \param ctl CTL handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified CTL handle and frees all associated + * resources. + */ +int +snd_ctl_close (snd_ctl_t * ctl) +{ + free (ctl); + return 0; +} + +/** + * \brief Get card related information + * \param ctl CTL handle + * \param info Card info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_card_info (snd_ctl_t * ctl, snd_ctl_card_info_t * info) +{ + + memset (info, 0, sizeof (*info)); + info->info = &ctl->info; + + return 0; +} + +/** + * \brief Obtain the card name. + * \param card Card number + * \param name Result - card name corresponding to card number + * \result zero if success, otherwise a negative error code + */ +int +snd_card_get_name (int card, char **name) +{ + char tmp[256]; + + sprintf (tmp, "OSS%d", card); + + *name = strdup (tmp); + return 0; +} + +int +snd_card_get_longname (int card, char **name) +{ + oss_card_info ci; + + ci.card = card; + if (ioctl (mixer_fd, SNDCTL_CARDINFO, &ci) == -1) + return -errno; + + *name = strdup (ci.longname); + return 0; +} + +/** + * \brief Get next PCM device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_pcm_next_device (snd_ctl_t * ctl, int *device) +{ + ALIB_INIT (); + + dbg_printf ("snd_ctl_pcm_next_device(%d)\n", *device); + + if (*device < 0) + *device = 0; + else + { + *device = *device + 1; + } + + while (1) + { + if (*device < 0 || *device >= sysinfo.numaudios) + { + *device = -1; + return 0; + } + + ctl->ainfo.dev = *device; + if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ctl->ainfo) < 0) + return -errno; + + if (ctl->ainfo.card_number == ctl->info.card) + { + return 0; + } + + *device = *device + 1; + } + + *device = -1; + return 0; +} + +/** + * \brief Get info about a PCM device + * \param ctl CTL handle + * \param info PCM device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_pcm_info (snd_ctl_t * ctl, snd_pcm_info_t * info) +{ + dbg_printf ("snd_ctl_pcm_info()\n"); + memset (info, 0, sizeof (*info)); + info->ainfo = &ctl->ainfo; + return 0; +} + +/** + * \brief Get card mixer name from a CTL card info + * \param obj CTL card info + * \return card mixer name + */ +const char * +snd_ctl_card_info_get_mixername (const snd_ctl_card_info_t * obj) +{ + return obj->info->longname; +} + +/** + * \brief Get info about a RawMidi device + * \param ctl CTL handle + * \param info RawMidi device id/info pointer + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_rawmidi_info (snd_ctl_t * ctl, snd_rawmidi_info_t * info) +{ + dbg_printf ("snd_ctl_rawmidi_info()\n"); + + return 0; +} + +/** + * \brief Get next RawMidi device number + * \param ctl CTL handle + * \param device current device on entry and next device on return + * \return 0 on success otherwise a negative error code + */ +int +snd_ctl_rawmidi_next_device (snd_ctl_t * ctl, int *device) +{ + dbg_printf ("snd_ctl_rawmidi_next_device()\n"); + + if (*device < 0) + *device = 0; + else + *device = -1; + + return 0; +} + +/** + * \brief Get card identifier from a CTL card info + * \param obj CTL card info + * \return card identifier + */ +const char * +snd_ctl_card_info_get_id (const snd_ctl_card_info_t * obj) +{ + dbg_printf ("snd_ctl_card_info_get_id()\n"); + + return "snd_ctl_card_info_get_id"; +} diff --git a/lib/libsalsa/misc.c b/lib/libsalsa/misc.c new file mode 100644 index 0000000..9af2408 --- /dev/null +++ b/lib/libsalsa/misc.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +snd_config_t *snd_config = NULL; + +const char * +snd_strerror (int errnum) +{ + if (errnum < 0) + errnum = -errnum; + + return strerror (errnum);; +} + +/** + * \brief Dumps the contents of a configuration node or tree. + * \param config Handle to the (root) configuration node. + * \param out Output handle. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_config_save (snd_config_t * config, snd_output_t * out) +{ + dbg_printf ("snd_config_save()\n"); + + return 0; +} + +/** + * \brief Searches for a node in a configuration tree. + * \param config Handle to the root of the configuration (sub)tree to search. + * \param key Search key: one or more node keys, separated with dots. + * \param result The function puts the handle to the node found at the address + * specified by \p result. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_config_search (snd_config_t * config, const char *key, + snd_config_t ** result) +{ + dbg_printf ("snd_config_search()\n"); + + return 0; +} + +/** + * \brief Updates #snd_config by rereading the global configuration files (if needed). + * \return A non-negative value if successful, otherwise a negative error code. * \retval 0 No action is needed. + * \retval 1 The configuration tree has been rebuilt. + * + * The global configuration files are specified in the environment variable + * \c ALSA_CONFIG_PATH. If this is not set, the default value is + * "/usr/share/alsa/alsa.conf". + * + * \warning If the configuration tree is reread, all string pointers and + * configuration node handles previously obtained from this tree become invalid. + */ +int +snd_config_update (void) +{ + dbg_printf ("snd_config_update()\n"); + + return 0; +} + +/** + * \brief Frees the global configuration tree in #snd_config. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_config_update_free_global (void) +{ + dbg_printf ("snd_config_update_free_global()\n"); + + return 0; +} + +/** + * \brief Sets the error handler. + * \param handler The pointer to the new error handler function. + * + * This function sets a new error handler, or (if \c handler is \c NULL) + * the default one which prints the error messages to \c stderr. + */ +int +snd_lib_error_set_handler (snd_lib_error_handler_t handler) +{ + dbg_printf ("snd_lib_error_set_handler()\n"); + return 0; +} diff --git a/lib/libsalsa/mix.c b/lib/libsalsa/mix.c new file mode 100644 index 0000000..5131518 --- /dev/null +++ b/lib/libsalsa/mix.c @@ -0,0 +1,1125 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * Parts of the code is derived from the alsa-lib package that is + * copyrighted by Jaroslav Kysela and the other ALSA team members. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +#define SND_VERS(a, b, c) (a<<16|b<<8|c) + +typedef struct _snd_mixer +{ + int mixdev; + int nrext; + + oss_mixerinfo info; + + snd_mixer_elem_t *elems; +} snd_mixer_t; + +#define MAX_MIXERS 32 +static snd_mixer_t *mixers[MAX_MIXERS]; +static int nmixers = 0; + +typedef struct _snd_mixer_selem_id +{ + int number; + char name[32]; +} snd_mixer_selem_id_t; + +typedef struct _snd_mixer_class +{ + int dummy; +} snd_mixer_class_t; + +typedef struct _snd_mixer_elem +{ + snd_mixer_t *mixer; + int ctrl; + oss_mixext ext; + + snd_mixer_elem_t *next; + + int low, high; +} snd_mixer_elem_t; + +/** + * \brief Opens an empty mixer + * \param mixerp Returned mixer handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_open (snd_mixer_t ** mixerp, int mode) +{ + snd_mixer_t *mixer; + dbg_printf2 ("snd_mixer_open()\n"); + + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + if ((mixer = malloc (sizeof (*mixer))) == NULL) + return -ENOMEM; + + memset (mixer, 0, sizeof (*mixer)); + *mixerp = mixer; + + return 0; +} + +/** + * \brief Attach an HCTL to an opened mixer + * \param mixer Mixer handle + * \param name HCTL name (see #snd_hctl_open) + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_attach (snd_mixer_t * mixer, const char *name) +{ + int dev = 0; + + ALIB_INIT (); + dbg_printf2 ("snd_mixer_attach(%s)\n", name); + + + if (strcmp (name, "default") == 0) + dev = 0; + else if (name[0] == 'h' && name[1] == 'w' && name[2] == ':') + { + if (sscanf (name + 3, "%d", &dev) != 1) + return -ENOENT; + + if (dev < 0 || dev >= sysinfo.nummixers) + return -ENXIO; + } + else + return -ENOENT; + + mixer->mixdev = dev; + + mixer->info.dev = dev; + if (ioctl (mixer_fd, SNDCTL_MIXERINFO, &mixer->info) == -1) + return -errno; + + mixer->nrext = mixer->info.nrext; + + if (nmixers < MAX_MIXERS) + mixers[nmixers++] = mixer; + + return 0; +} + + +/** + * \brief Close a mixer and free all related resources + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_close (snd_mixer_t * mixer) +{ + dbg_printf2 ("snd_mixer_close()\n"); + + free (mixer); + return 0; +} + +/** + * \brief Register mixer simple element class + * \param mixer Mixer handle + * \param options Options container (not used now) + * \param classp Pointer to returned mixer simple element class handle (or NULL) * \return 0 on success otherwise a negative error code + */ +#if 1 +int +snd_mixer_selem_register (snd_mixer_t * mixer, + struct snd_mixer_selem_regopt *arg, + snd_mixer_class_t ** classp) +#else +int +snd_mixer_selem_register (snd_mixer_t * mixer, void *arg, + snd_mixer_class_t ** classp) +#endif +{ + snd_mixer_class_t *class; + + dbg_printf2 ("snd_mixer_selem_register()\n"); + + if (classp == NULL) /* Why this call was ever made ? */ + return 0; + + if ((class = malloc (sizeof (*class))) == NULL) + return -ENOMEM; + + memset (class, 0, sizeof (*class)); + *classp = class; + + return 0; +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int +snd_mixer_selem_has_playback_volume (snd_mixer_elem_t * elem) +{ + dbg_printf2 ("snd_mixer_selem_has_playback_volume(%x)\n", elem); + fflush (stdout); + + if (elem->ext.type == MIXT_STEREOSLIDER) + return 1; + if (elem->ext.type == MIXT_MONOSLIDER) + return 1; + if (elem->ext.type == MIXT_SLIDER) + return 1; + + return 0; +} + +/** + * \brief Return info about playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int +snd_mixer_selem_has_playback_volume_joined (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_playback_volume_joined()\n"); + + return elem->ext.type != MIXT_STEREOSLIDER; +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int +snd_mixer_selem_has_capture_volume (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_capture_volume()\n"); + + return 0; +} + + +/** + * \brief Return info about playback switch control existence of a mixer simple +element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int +snd_mixer_selem_has_playback_switch (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_playback_switch()\n"); + + if (elem->ext.type == MIXT_ONOFF || elem->ext.type == MIXT_MUTE) + return 1; + return 0; +} + +/** + * \brief Set value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_playback_volume (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + long value) +{ + int vol, range; + oss_mixer_value rec; + + dbg_printf2 ("snd_mixer_selem_set_playback_volume(%ld)\n", value); + + if (value < elem->low) + value = elem->low; + if (value > elem->high) + value = elem->high; + + range = elem->high - elem->low; + if (range == 0) + range = 100; + value -= elem->low; + vol = (value * elem->ext.maxvalue) / range; + + rec.dev = elem->ext.dev; + rec.ctrl = elem->ext.ctrl; + rec.ctrl = elem->ext.ctrl; + rec.timestamp = elem->ext.timestamp; + rec.value = vol | (vol << 8); + + if (ioctl (mixer_fd, SNDCTL_MIX_WRITE, &rec) == -1) + return -errno; + + return 0; +} + +/** + * \brief Set range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +#if SND_LIB_VERSION > SND_VERS(1,0,9) +int +#else +void +#endif +snd_mixer_selem_set_capture_volume_range (snd_mixer_elem_t * elem, + long min, long max) +{ + dbg_printf ("snd_mixer_selem_set_capture_volume_range()\n"); + +#if SND_LIB_VERSION > SND_VERS(1,0,9) + return 0; +#endif +} + +/** + * \brief Set value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_capture_volume (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + long value) +{ + dbg_printf ("snd_mixer_selem_set_capture_volume()\n"); + + return 0; +} + +/** + * \brief Set range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min minimum volume value + * \param max maximum volume value + */ +#if SND_LIB_VERSION > SND_VERS(1,0,9) +int +#else +void +#endif +snd_mixer_selem_set_playback_volume_range (snd_mixer_elem_t * elem, + long min, long max) +{ + dbg_printf2 ("snd_mixer_selem_set_playback_volume_range(%s, %d, %d)\n", + elem->ext.extname, min, max); + + elem->low = min; + elem->high = max; + +#if SND_LIB_VERSION > SND_VERS(1,0,9) + return 0; +#endif +} + +/** + * \brief Return value of playback volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_get_playback_volume (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + long *value) +{ + int vol, range, left, right; + oss_mixer_value rec; + + dbg_printf2 ("snd_mixer_selem_get_playback_volume()\n"); + + rec.dev = elem->ext.dev; + rec.ctrl = elem->ext.ctrl; + rec.timestamp = elem->ext.timestamp; + + if (ioctl (mixer_fd, SNDCTL_MIX_READ, &rec) == -1) + return -errno; + + left = rec.value & 0xff; + right = (rec.value >> 8) & 0xff; + + if (left > right) + vol = left; + else + vol = right; + range = elem->high - elem->low; + + vol = (vol * range) / elem->ext.maxvalue; + vol += elem->low; + *value = vol; + + return 0; +} + +/** + * \brief Get range for playback volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +#if SND_LIB_VERSION > SND_VERS(1,0,9) +int +#else +void +#endif +snd_mixer_selem_get_playback_volume_range (snd_mixer_elem_t * elem, + long *min, long *max) +{ + dbg_printf2 ("snd_mixer_selem_get_playback_volume_range()\n"); +#if 1 + *min = elem->low; + *max = elem->high; +#endif + +#if SND_LIB_VERSION > SND_VERS(1,0,9) + return 0; +#endif +} + +/** + * \brief get first element for a mixer + * \param mixer Mixer handle + * \return pointer to first element + */ +snd_mixer_elem_t * +snd_mixer_first_elem (snd_mixer_t * mixer) +{ + dbg_printf2 ("snd_mixer_first_elem()\n"); + + return mixer->elems; +} + +/** + * \brief get next mixer element + * \param elem mixer element + * \return pointer to next element + */ +snd_mixer_elem_t * +snd_mixer_elem_next (snd_mixer_elem_t * elem) +{ + dbg_printf2 ("snd_mixer_elem_next(%x/%d)\n", elem, elem); + + if (elem == NULL || (long) elem < 4096) + { + dbg_printf2 ("Returning NULL\n"); + return NULL; + } + + if (elem->next == NULL) + dbg_printf ("No more elemsnts\n"); + else + dbg_printf2 ("Returning %d/%s\n", elem->next->ctrl, + elem->next->ext.extname); + return elem->next; +} + +/** + * \brief Find a mixer simple element + * \param mixer Mixer handle + * \param id Mixer simple element identifier + * \return mixer simple element handle or NULL if not found + * + * Wuld somebody kindly explain me what in hell is the logic + * behind this idiotic "simple" mixer stuff. + */ +snd_mixer_elem_t * +snd_mixer_find_selem (snd_mixer_t * mixer, const snd_mixer_selem_id_t * id) +{ + int i; + + dbg_printf2 ("snd_mixer_find_selem(%d/%s)\n", id->number, id->name); + + if (*id->name == 0 && id->number == 0) + return NULL; + + for (i = 0; i < mixer->nrext; i++) + { + oss_mixext *ext = &mixer->elems[i].ext; + + if (ext->type == MIXT_GROUP || + ext->type == MIXT_DEVROOT || ext->type == MIXT_MARKER) + continue; + + if (strcasecmp (ext->extname, id->name) == 0) + { + return &mixer->elems[i]; + } + + if (ext->ctrl == id->number) + { + return &mixer->elems[i]; + } + } + + return NULL; +} + +/** + * \brief Handle pending mixer events invoking callbacks + * \param mixer Mixer handle + * \return 0 otherwise a negative error code on failure + */ +int +snd_mixer_handle_events (snd_mixer_t * mixer) +{ + dbg_printf2 ("snd_mixer_handle_events()\n"); + // NOP +} + +/** + * \brief Load a mixer elements + * \param mixer Mixer handle + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_load (snd_mixer_t * mixer) +{ + snd_mixer_elem_t *elems; + int i, n = 0; + + dbg_printf2 ("snd_mixer_load()\n"); + + if (mixer->elems != NULL) + free (mixer->elems); + + if ((elems = malloc (sizeof (*elems) * mixer->nrext)) == NULL) + return -ENOMEM; + + memset (elems, 0, sizeof (*elems) * mixer->nrext); + + for (i = 0; i < mixer->nrext; i++) + { + oss_mixext *ext = &elems[n].ext; + snd_mixer_elem_t *elem; + + elem = &elems[n]; + + ext->dev = mixer->mixdev; + ext->ctrl = i; + + if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, ext) < 0) + { + int e = errno; + perror ("SNDCTL_MIX_EXTINFO"); + return -e; + } + + if (ext->type == MIXT_DEVROOT) + continue; + if (ext->type == MIXT_GROUP) + continue; + if (ext->type == MIXT_MARKER) + continue; + + elem->low = 0; + elem->high = ext->maxvalue; + elem->ctrl = elem->ext.ctrl; + + if (n > 0) + elems[n - 1].next = &elems[n]; + + n++; + } + + mixer->nrext = n; + mixer->elems = elems; + return 0; +} + +/** + * \brief Get name part of mixer simple element identifier + * \param elem Mixer simple element handle + * \return name part of simple element identifier + */ +const char * +snd_mixer_selem_get_name (snd_mixer_elem_t * elem) +{ + dbg_printf2 ("snd_mixer_selem_get_name()\n"); + + return elem->ext.extname; +} + +/** + * \brief Set index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val index part + */ +void +snd_mixer_selem_id_set_index (snd_mixer_selem_id_t * obj, unsigned int val) +{ + dbg_printf2 ("snd_mixer_selem_id_set_index(%u)\n", val); + + obj->number = val; +} + +/** + * \brief Set name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \param val name part + */ +void +snd_mixer_selem_id_set_name (snd_mixer_selem_id_t * obj, const char *val) +{ + dbg_printf2 ("snd_mixer_selem_id_set_name(%s)\n", val); + + strcpy (obj->name, val); +} + +/** + * \brief get size of #snd_mixer_selem_id_t + * \return size in bytes + */ +size_t +snd_mixer_selem_id_sizeof () +{ + return sizeof (snd_mixer_selem_id_t); +} + + +/** + * \brief Get info about the active state of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not active, 1 if active + */ +int +snd_mixer_selem_is_active (snd_mixer_elem_t * elem) +{ + dbg_printf2 ("snd_mixer_selem_is_active()\n"); + return 1; +} + +/** + * \brief Return value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_get_capture_switch (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + int *value) +{ + dbg_printf ("snd_mixer_selem_get_capture_switch()\n"); + + *value = 0; + return 0; +} + +/** + * \brief Return value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_get_playback_switch (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + int *value) +{ + oss_mixer_value rec; + + dbg_printf ("snd_mixer_selem_get_playback_switch()\n"); + + *value = 0; + + rec.dev = elem->ext.dev; + rec.ctrl = elem->ext.ctrl; + rec.ctrl = elem->ext.ctrl; + rec.timestamp = elem->ext.timestamp; + + if (ioctl (mixer_fd, SNDCTL_MIX_READ, &rec) == -1) + return -errno; + + *value = !!rec.value; + return 0; +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int +snd_mixer_selem_has_capture_channel (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel) +{ + dbg_printf ("snd_mixer_selem_has_capture_channel()\n"); + + return (channel < 2); +} + +/** + * \brief Return info about capture switch control existence of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if no control is present, 1 if it's present + */ +int +snd_mixer_selem_has_capture_switch (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_capture_switch()\n"); + + return 0; +} + +/** + * \brief Return info about capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int +snd_mixer_selem_has_capture_switch_joined (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_capture_switch_joined()\n"); + + return 1; +} + +/** + * \brief Get info about channels of capture stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int +snd_mixer_selem_is_capture_mono (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_is_capture_mono()\n"); + return 0; +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if not mono, 1 if mono + */ +int +snd_mixer_selem_is_playback_mono (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_is_playback_mono()\n"); + return 0; +} + +/** + * \brief Set value of capture switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_capture_switch (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + int value) +{ + dbg_printf ("snd_mixer_selem_set_capture_switch()\n"); + + return 0; +} + +/** + * \brief Set value of capture switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_capture_switch_all (snd_mixer_elem_t * elem, int value) +{ + dbg_printf ("snd_mixer_selem_set_capture_switch_all()\n"); + + return 0; +} + +/** + * \brief Set value of playback switch control for all channels of a mixer simple element + * \param elem Mixer simple element handle + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_playback_switch_all (snd_mixer_elem_t * elem, int value) +{ + oss_mixer_value rec; + + dbg_printf ("snd_mixer_selem_set_playback_switch_all()\n"); + + rec.dev = elem->ext.dev; + rec.ctrl = elem->ext.ctrl; + rec.ctrl = elem->ext.ctrl; + rec.timestamp = elem->ext.timestamp; + rec.value = !!value; + + if (ioctl (mixer_fd, SNDCTL_MIX_WRITE, &rec) == -1) + return -errno; + + return 0; +} + +/** + * \brief Return value of capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value pointer to returned value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_get_capture_volume (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + long *value) +{ + dbg_printf ("snd_mixer_selem_get_capture_volume()\n"); + + *value = 0; + return 0; +} + +/** + * \brief Get mixer simple element identifier + * \param elem Mixer simple element handle + * \param id returned mixer simple element identifier + */ +void +snd_mixer_selem_get_id (snd_mixer_elem_t * elem, snd_mixer_selem_id_t * id) +{ + dbg_printf ("snd_mixer_selem_get_id()\n"); + // What in hell is this? + + id->number = elem->ctrl; + strcpy (id->name, elem->ext.extname); + dbg_printf ("ID=%d / %s\n", id->number, id->name); +} + +/** + * \brief Get name part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return name part + */ +const char * +snd_mixer_selem_id_get_name (const snd_mixer_selem_id_t * obj) +{ + dbg_printf ("snd_mixer_selem_id_get_name()=%s\n", obj->name); +//return "Objname"; + return obj->name; +} + +/** + * \brief Get index part of a mixer simple element identifier + * \param obj Mixer simple element identifier + * \return index part + */ +unsigned int +snd_mixer_selem_id_get_index (const snd_mixer_selem_id_t * obj) +{ + dbg_printf ("snd_mixer_selem_id_get_index()\n"); + + return 0; +} + + +/** + * \brief Get elements count for a mixer + * \param mixer mixer handle + * \return elements count + */ +unsigned int +snd_mixer_get_count (const snd_mixer_t * obj) +{ + dbg_printf ("snd_mixer_get_count()\n"); + + return obj->nrext; +} + +/** + * \brief get poll descriptors + * \param mixer Mixer handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int +snd_mixer_poll_descriptors (snd_mixer_t * mixer, struct pollfd *pfds, + unsigned int space) +{ + dbg_printf ("snd_mixer_poll_descriptors()\n"); + + return 0; +} + +/** + * \brief get count of poll descriptors for mixer handle + * \param mixer Mixer handle + * \return count of poll descriptors + */ +int +snd_mixer_poll_descriptors_count (snd_mixer_t * mixer) +{ + dbg_printf ("snd_mixer_poll_descriptors_count()\n"); + + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param mixer Mixer handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int +snd_mixer_poll_descriptors_revents (snd_mixer_t * mixer, struct pollfd *pfds, + unsigned int nfds, + unsigned short *revents) +{ + dbg_printf ("snd_mixer_poll_descriptors_revents()\n"); + + return 0; +} + +/** + * \brief Set callback function for a mixer + * \param mixer mixer handle + * \param callback callback function + */ +void +snd_mixer_set_callback (snd_mixer_t * obj, snd_mixer_callback_t val) +{ + dbg_printf0 ("snd_mixer_set_callback()\n"); + +} + +/** + * \brief Get range for capture volume of a mixer simple element + * \param elem Mixer simple element handle + * \param min Pointer to returned minimum + * \param max Pointer to returned maximum + */ +#if SND_LIB_VERSION > SND_VERS(1,0,9) +int +#else +void +#endif +snd_mixer_selem_get_capture_volume_range (snd_mixer_elem_t * elem, + long *min, long *max) +{ + dbg_printf ("snd_mixer_selem_get_capture_volume_range()\n"); + + *min = 0; + *max = 100; + +#if SND_LIB_VERSION > SND_VERS(1,0,9) + return 0; +#endif +} + +/** + * \brief Return true if mixer simple element is an enumerated control + * \param elem Mixer simple element handle + * \return 0 normal volume/switch control, 1 enumerated control + */ +int +snd_mixer_selem_is_enumerated (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_is_enumerated()\n"); + + return 0; +} + +/** + * \brief get the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param itemp the pointer to store the index of the enumerated item + * \return 0 if successful, otherwise a negative error code + */ +int +snd_mixer_selem_get_enum_item (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + unsigned int *itemp) +{ + dbg_printf ("snd_mixer_selem_get_enum_item()\n"); + + return 0; +} + +/** + * \brief Return the number of enumerated items of the given mixer simple element + * \param elem Mixer simple element handle + * \return the number of enumerated items, otherwise a negative error code + */ +int +snd_mixer_selem_get_enum_items (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_get_enum_items()\n"); + return 0; +} + +/** + * \brief get the enumerated item string for the given mixer simple element + * \param elem Mixer simple element handle + * \param item the index of the enumerated item to query + * \param maxlen the maximal length to be stored + * \param buf the buffer to store the name string + * \return 0 if successful, otherwise a negative error code + */ +int +snd_mixer_selem_get_enum_item_name (snd_mixer_elem_t * elem, + unsigned int item, + size_t maxlen, char *buf) +{ + dbg_printf ("snd_mixer_selem_get_enum_item_name()\n"); + strncpy (buf, "Enum", maxlen); + buf[maxlen - 1] = 0; + + return 0; +} + +/** + * \brief Return info about capture volume control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int +snd_mixer_selem_has_capture_volume_joined (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_capture_volume_joined()\n"); + return elem->ext.type != MIXT_STEREOSLIDER; +} + +/** + * \brief Get info about channels of playback stream of a mixer simple element + * \param elem Mixer simple element handle + * \param channel Mixer simple element channel identifier + * \return 0 if channel is not present, 1 if present + */ +int +snd_mixer_selem_has_playback_channel (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel) +{ + dbg_printf ("snd_mixer_selem_has_playback_channel(%s, %d)\n", + elem->ext.extname, channel); + + if (elem->ext.type == MIXT_SLIDER && channel == 0) + return 1; + if (elem->ext.type == MIXT_MONOSLIDER && channel == 0) + return 1; + if (elem->ext.type == MIXT_STEREOSLIDER && channel < 2) + return 1; + + return 0; +} + +/** + * \brief Return info about playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \return 0 if control is separated per channel, 1 if control acts on all channels together + */ +int +snd_mixer_selem_has_playback_switch_joined (snd_mixer_elem_t * elem) +{ + dbg_printf ("snd_mixer_selem_has_playback_switch_joined()\n"); + + return 0; +} + +/** + * \brief copy one #snd_mixer_selem_id_t to another + * \param dst pointer to destination + * \param src pointer to source + */ +void +snd_mixer_selem_id_copy (snd_mixer_selem_id_t * dst, + const snd_mixer_selem_id_t * src) +{ + dbg_printf ("snd_mixer_selem_id_copy()\n"); + memcpy (dst, src, sizeof (*dst)); +} + + +/** + * \brief set the current selected enumerated item for the given mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param item the enumerated item index + * \return 0 if successful, otherwise a negative error code + */ +int +snd_mixer_selem_set_enum_item (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + unsigned int item) +{ + dbg_printf ("snd_mixer_selem_set_enum_item()\n"); + + return 0; +} + +/** + * \brief Set value of playback switch control of a mixer simple element + * \param elem Mixer simple element handle + * \param channel mixer simple element channel identifier + * \param value control value + * \return 0 on success otherwise a negative error code + */ +int +snd_mixer_selem_set_playback_switch (snd_mixer_elem_t * elem, + snd_mixer_selem_channel_id_t channel, + int value) +{ + dbg_printf ("snd_mixer_selem_set_playback_switch()\n"); + + return 0; +} + +/** + * * \brief Return true if mixer simple element has only one volume control for both playback and capture + * * \param elem Mixer simple element handle + * * \return 0 separated control, 1 common control + * */ +int +snd_mixer_selem_has_common_volume (snd_mixer_elem_t * elem) +{ + return 0; // TODO +} + +/** + * * \brief Return true if mixer simple element has only one switch control for both playback and capture + * * \param elem Mixer simple element handle + * * \return 0 separated control, 1 common control + * */ +int +snd_mixer_selem_has_common_switch (snd_mixer_elem_t * elem) +{ + return 0; // TODO +} diff --git a/lib/libsalsa/output.c b/lib/libsalsa/output.c new file mode 100644 index 0000000..0369a81 --- /dev/null +++ b/lib/libsalsa/output.c @@ -0,0 +1,411 @@ +/** + * \file output.c + * \brief Generic stdio-like output interface + * \author Abramo Bagnara <abramo@alsa-project.org> + * \date 2000 + * + * Generic stdio-like output interface + */ +/* + * Output object + * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include "local.h" + +#ifndef DOC_HIDDEN +typedef struct _snd_output_ops +{ + int (*close) (snd_output_t * output); + int (*print) (snd_output_t * output, const char *format, va_list args); + int (*puts) (snd_output_t * output, const char *str); + int (*putch) (snd_output_t * output, int c); + int (*flush) (snd_output_t * output); +} snd_output_ops_t; + +struct _snd_output +{ + snd_output_type_t type; + snd_output_ops_t *ops; + void *private_data; +}; +#endif + +/** + * \brief Closes an output handle. + * \param output The output handle to be closed. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_output_close (snd_output_t * output) +{ + int err = output->ops->close (output); + free (output); + return err; +} + +/** + * \brief Writes formatted output (like \c fprintf(3)) to an output handle. + * \param output The output handle. + * \param format Format string in \c fprintf format. + * \param ... Other \c fprintf arguments. + * \return The number of characters written, or a negative error code. + */ +int +snd_output_printf (snd_output_t * output, const char *format, ...) +{ + int result; + va_list args; + va_start (args, format); + result = output->ops->print (output, format, args); + va_end (args); + return result; +} + +/** + * \brief Writes formatted output (like \c fprintf(3)) to an output handle. + * \param output The output handle. + * \param format Format string in \c fprintf format. + * \param args Other \c fprintf arguments. + * \return The number of characters written, or a negative error code. + */ +int +snd_output_vprintf (snd_output_t * output, const char *format, va_list args) +{ + return output->ops->print (output, format, args); +} + +/** + * \brief Writes a string to an output handle (like \c fputs(3)). + * \param output The output handle. + * \param str Pointer to the string. + * \return Zero if successful, otherwise a negative error code or \c EOF. + */ +int +snd_output_puts (snd_output_t * output, const char *str) +{ + return output->ops->puts (output, str); +} + +/** + * \brief Writes a character to an output handle (like \c putc(3)). + * \param output The output handle. + * \param c The character. + * \return Zero if successful, otherwise a negative error code or \c EOF. + */ +int +snd_output_putc (snd_output_t * output, int c) +{ + return output->ops->putch (output, c); +} + +/** + * \brief Flushes an output handle (like fflush(3)). + * \param output The output handle. + * \return Zero if successful, otherwise \c EOF. + * + * If the underlying destination is a stdio stream, this function calls + * \c fflush. If the underlying destination is a memory buffer, the write + * position is reset to the beginning of the buffer. \c =:-o + */ +int +snd_output_flush (snd_output_t * output) +{ + return output->ops->flush (output); +} + +#ifndef DOC_HIDDEN +typedef struct _snd_output_stdio +{ + int close; + FILE *fp; +} snd_output_stdio_t; + +static int +snd_output_stdio_close (snd_output_t * output ATTRIBUTE_UNUSED) +{ + snd_output_stdio_t *stdio = output->private_data; + if (stdio->close) + fclose (stdio->fp); + free (stdio); + return 0; +} + +static int +snd_output_stdio_print (snd_output_t * output, const char *format, + va_list args) +{ + snd_output_stdio_t *stdio = output->private_data; + return vfprintf (stdio->fp, format, args); +} + +static int +snd_output_stdio_puts (snd_output_t * output, const char *str) +{ + snd_output_stdio_t *stdio = output->private_data; + return fputs (str, stdio->fp); +} + +static int +snd_output_stdio_putc (snd_output_t * output, int c) +{ + snd_output_stdio_t *stdio = output->private_data; + return putc (c, stdio->fp); +} + +static int +snd_output_stdio_flush (snd_output_t * output) +{ + snd_output_stdio_t *stdio = output->private_data; + return fflush (stdio->fp); +} + +static snd_output_ops_t snd_output_stdio_ops = { + .close = snd_output_stdio_close, + .print = snd_output_stdio_print, + .puts = snd_output_stdio_puts, + .putch = snd_output_stdio_putc, + .flush = snd_output_stdio_flush, +}; + +#endif + +/** + * \brief Creates a new output object using an existing stdio \c FILE pointer. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \param fp The \c FILE pointer to write to. Characters are written + * to the file starting at the current file position. + * \param close Close flag. Set this to 1 if #snd_output_close should close + * \p fp by calling \c fclose. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_output_stdio_attach (snd_output_t ** outputp, FILE * fp, int _close) +{ + snd_output_t *output; + snd_output_stdio_t *stdio; + assert (outputp && fp); + stdio = calloc (1, sizeof (*stdio)); + if (!stdio) + return -ENOMEM; + output = calloc (1, sizeof (*output)); + if (!output) + { + free (stdio); + return -ENOMEM; + } + stdio->fp = fp; + stdio->close = _close; + output->type = SND_OUTPUT_STDIO; + output->ops = &snd_output_stdio_ops; + output->private_data = stdio; + *outputp = output; + return 0; +} + +/** + * \brief Creates a new output object writing to a file. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \param file The name of the file to open. + * \param mode The open mode, like \c fopen(3). + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_output_stdio_open (snd_output_t ** outputp, const char *file, + const char *mode) +{ + int err; + FILE *fp = fopen (file, mode); + if (!fp) + { + //SYSERR("fopen"); + return -errno; + } + err = snd_output_stdio_attach (outputp, fp, 1); + if (err < 0) + fclose (fp); + return err; +} + +#ifndef DOC_HIDDEN + +typedef struct _snd_output_buffer +{ + unsigned char *buf; + size_t alloc; + size_t size; +} snd_output_buffer_t; + +static int +snd_output_buffer_close (snd_output_t * output ATTRIBUTE_UNUSED) +{ + snd_output_buffer_t *buffer = output->private_data; + free (buffer->buf); + free (buffer); + return 0; +} + +static int +snd_output_buffer_need (snd_output_t * output, size_t size) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t _free = buffer->alloc - buffer->size; + size_t alloc; + unsigned char *buf; + + if (_free >= size) + return _free; + if (buffer->alloc == 0) + alloc = 256; + else + alloc = buffer->alloc; + while (alloc < size) + alloc *= 2; + buf = realloc (buffer->buf, alloc); + if (!buf) + return -ENOMEM; + buffer->buf = buf; + buffer->alloc = alloc; + return buffer->alloc - buffer->size; +} + +static int +snd_output_buffer_print (snd_output_t * output, const char *format, + va_list args) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t size = 256; + int result; + result = snd_output_buffer_need (output, size); + if (result < 0) + return result; + result = vsnprintf (buffer->buf + buffer->size, size, format, args); + assert (result >= 0); + if ((size_t) result <= size) + { + buffer->size += result; + return result; + } + size = result; + result = snd_output_buffer_need (output, size); + if (result < 0) + return result; + result = vsnprintf (buffer->buf + buffer->size, result, format, args); + assert (result == (int) size); + buffer->size += result; + return result; +} + +static int +snd_output_buffer_puts (snd_output_t * output, const char *str) +{ + snd_output_buffer_t *buffer = output->private_data; + size_t size = strlen (str); + int err; + err = snd_output_buffer_need (output, size); + if (err < 0) + return err; + memcpy (buffer->buf + buffer->size, str, size); + buffer->size += size; + return size; +} + +static int +snd_output_buffer_putc (snd_output_t * output, int c) +{ + snd_output_buffer_t *buffer = output->private_data; + int err; + err = snd_output_buffer_need (output, 1); + if (err < 0) + return err; + buffer->buf[buffer->size++] = c; + return 0; +} + +static int +snd_output_buffer_flush (snd_output_t * output ATTRIBUTE_UNUSED) +{ + snd_output_buffer_t *buffer = output->private_data; + buffer->size = 0; + return 0; +} + +static snd_output_ops_t snd_output_buffer_ops = { + .close = snd_output_buffer_close, + .print = snd_output_buffer_print, + .puts = snd_output_buffer_puts, + .putch = snd_output_buffer_putc, + .flush = snd_output_buffer_flush, +}; +#endif + +/** + * \brief Returns the address of the buffer of a #SND_OUTPUT_TYPE_BUFFER output handle. + * \param output The output handle. + * \param buf The functions puts the current address of the buffer at the + * address specified by \p buf. + * \return The current size of valid data in the buffer. + * + * The address of the buffer may become invalid when output functions or + * #snd_output_close are called. + */ +size_t +snd_output_buffer_string (snd_output_t * output, char **buf) +{ + snd_output_buffer_t *buffer = output->private_data; + *buf = buffer->buf; + return buffer->size; +} + +/** + * \brief Creates a new output object with an auto-extending memory buffer. + * \param outputp The function puts the pointer to the new output object + * at the address specified by \p outputp. + * \return Zero if successful, otherwise a negative error code. + */ +int +snd_output_buffer_open (snd_output_t ** outputp) +{ + snd_output_t *output; + snd_output_buffer_t *buffer; + assert (outputp); + buffer = calloc (1, sizeof (*buffer)); + if (!buffer) + return -ENOMEM; + output = calloc (1, sizeof (*output)); + if (!output) + { + free (buffer); + return -ENOMEM; + } + buffer->buf = NULL; + buffer->alloc = 0; + buffer->size = 0; + output->type = SND_OUTPUT_BUFFER; + output->ops = &snd_output_buffer_ops; + output->private_data = buffer; + *outputp = output; + return 0; +} diff --git a/lib/libsalsa/pcm.c b/lib/libsalsa/pcm.c new file mode 100644 index 0000000..a305e54 --- /dev/null +++ b/lib/libsalsa/pcm.c @@ -0,0 +1,3114 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * Parts of the code is derived from the alsa-lib package that is + * copyrighted by Jaroslav Kysela and the other ALSA team members. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#define USE_VERSIONED_SYMBOLS +#define DO_VERSIONING +#define HAVE_ELF +#define PERIOD_SIZE 128 + +#include "local.h" + +#define PCMTYPE(v) [SND_PCM_TYPE_##v] = #v +#define STATE(v) [SND_PCM_STATE_##v] = #v +#define STREAM(v) [SND_PCM_STREAM_##v] = #v +#define READY(v) [SND_PCM_READY_##v] = #v +#define XRUN(v) [SND_PCM_XRUN_##v] = #v +#define SILENCE(v) [SND_PCM_SILENCE_##v] = #v +#define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v +#define ACCESS(v) [SND_PCM_ACCESS_##v] = #v +#define START(v) [SND_PCM_START_##v] = #v +#define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v +#define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v +#define FORMAT(v) [SND_PCM_FORMAT_##v] = #v +#define SUBFORMAT(v) [SND_PCM_SUBFORMAT_##v] = #v + +#define FORMATD(v, d) [SND_PCM_FORMAT_##v] = d +#define SUBFORMATD(v, d) [SND_PCM_SUBFORMAT_##v] = d + +static const char *snd_pcm_stream_names[] = { + STREAM (PLAYBACK), + STREAM (CAPTURE), +}; + +static const char *snd_pcm_state_names[] = { + STATE (OPEN), + STATE (SETUP), + STATE (PREPARED), + STATE (RUNNING), + STATE (XRUN), + STATE (DRAINING), + STATE (PAUSED), + STATE (SUSPENDED), + STATE (DISCONNECTED), +}; + +static const char *snd_pcm_access_names[] = { + ACCESS (MMAP_INTERLEAVED), + ACCESS (MMAP_NONINTERLEAVED), + ACCESS (MMAP_COMPLEX), + ACCESS (RW_INTERLEAVED), + ACCESS (RW_NONINTERLEAVED), +}; + +static const char *snd_pcm_format_descriptions[] = { + FORMATD (S8, "Signed 8 bit"), + FORMATD (U8, "Unsigned 8 bit"), + FORMATD (S16_LE, "Signed 16 bit Little Endian"), + FORMATD (S16_BE, "Signed 16 bit Big Endian"), + FORMATD (U16_LE, "Unsigned 16 bit Little Endian"), + FORMATD (U16_BE, "Unsigned 16 bit Big Endian"), + FORMATD (S24_LE, "Signed 24 bit Little Endian"), + FORMATD (S24_BE, "Signed 24 bit Big Endian"), + FORMATD (U24_LE, "Unsigned 24 bit Little Endian"), + FORMATD (U24_BE, "Unsigned 24 bit Big Endian"), + FORMATD (S32_LE, "Signed 32 bit Little Endian"), + FORMATD (S32_BE, "Signed 32 bit Big Endian"), + FORMATD (U32_LE, "Unsigned 32 bit Little Endian"), + FORMATD (U32_BE, "Unsigned 32 bit Big Endian"), + FORMATD (FLOAT_LE, "Float 32 bit Little Endian"), + FORMATD (FLOAT_BE, "Float 32 bit Big Endian"), + FORMATD (FLOAT64_LE, "Float 64 bit Little Endian"), + FORMATD (FLOAT64_BE, "Float 64 bit Big Endian"), + FORMATD (IEC958_SUBFRAME_LE, "IEC-958 Little Endian"), + FORMATD (IEC958_SUBFRAME_BE, "IEC-958 Big Endian"), + FORMATD (MU_LAW, "Mu-Law"), + FORMATD (A_LAW, "A-Law"), + FORMATD (IMA_ADPCM, "Ima-ADPCM"), + FORMATD (MPEG, "MPEG"), + FORMATD (GSM, "GSM"), + FORMATD (SPECIAL, "Special"), + FORMATD (S24_3LE, "Signed 24 bit Little Endian in 3bytes"), + FORMATD (S24_3BE, "Signed 24 bit Big Endian in 3bytes"), + FORMATD (U24_3LE, "Unsigned 24 bit Little Endian in 3bytes"), + FORMATD (U24_3BE, "Unsigned 24 bit Big Endian in 3bytes"), + FORMATD (S20_3LE, "Signed 20 bit Little Endian in 3bytes"), + FORMATD (S20_3BE, "Signed 20 bit Big Endian in 3bytes"), + FORMATD (U20_3LE, "Unsigned 20 bit Little Endian in 3bytes"), + FORMATD (U20_3BE, "Unsigned 20 bit Big Endian in 3bytes"), + FORMATD (S18_3LE, "Signed 18 bit Little Endian in 3bytes"), + FORMATD (S18_3BE, "Signed 18 bit Big Endian in 3bytes"), + FORMATD (U18_3LE, "Unsigned 18 bit Little Endian in 3bytes"), + FORMATD (U18_3BE, "Unsigned 18 bit Big Endian in 3bytes"), +}; + +struct _snd_pcm +{ + int fd; + int state; + oss_audioinfo info; + int stream, oss_mode; + int frame_size, sample_size, period_size; + int channels; + int periods; + snd_pcm_channel_area_t *area; +}; + +struct _snd_pcm_format_mask +{ + unsigned int mask; +}; + +struct _snd_pcm_status +{ + int dummy; +}; + +struct _snd_pcm_sw_params +{ + int dummy; +}; + +struct _snd_pcm_hw_params +{ + int speed; + int fmt, channels; + int oss_fmt; + + oss_audioinfo *info; + snd_pcm_t *pcm; + + int frame_size; + int sample_bits; + int access; +}; + +static int +parse_device (const char *nme, char *dspname) +{ + char *s; + oss_audioinfo ai; + int card = 0, port = 0, i; + char tmp[256], *name = tmp; + + strcpy (name, nme); + + if (name[0] != 'h') + return 0; + if (name[1] != 'w') + return 0; + if (name[2] != ':') + return 0; + + name += 3; + s = name; + + while (*s && *s != ',') + s++; + + if (*s == ',') + { + int n = 0; + + *s++ = 0; + if (sscanf (name, "%d", &card) != 1) + return 0; + if (sscanf (s, "%d", &port) != 1) + return 0; + + n = -1; + for (i = 0; i < sysinfo.numaudios; i++) + { + ai.dev = i; + if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ai) == -1) + continue; + + if (ai.card_number != card) + continue; + + n++; + if (port < n) + continue; + + sprintf (dspname, "/dev/dsp%d", i); + return 1; + } + return 0; + } + if (sscanf (name, "%d", &card) != 1) + return 0; + + for (i = 0; i < sysinfo.numaudios; i++) + { + ai.dev = i; + if (ioctl (mixer_fd, SNDCTL_AUDIOINFO, &ai) == -1) + continue; + + if (ai.card_number == card) + { + port = i; + sprintf (dspname, "/dev/dsp%d", port); + return 1; + } + } + + return 0; +} + +/** + * \brief Opens a PCM + * \param pcmp Returned PCM handle + * \param name ASCII identifier of the PCM handle + * \param stream Wanted stream + * \param mode Open mode (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC) + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_open (snd_pcm_t ** pcmp, const char *name, + snd_pcm_stream_t stream, int mode) +{ + snd_pcm_t *pcm; + int oss_mode = O_WRONLY; + char dspname[32]; + const char *devdsp; + + if ((devdsp = getenv("OSS_AUDIODEV")) == NULL) + devdsp = "/dev/dsp"; + + ALIB_INIT (); + + if (!alib_appcheck ()) + return -ENODEV; + + *pcmp = NULL; + + dbg_printf ("snd_pcm_open(%s, %x)\n", name, stream); + + if (mode != 0) + dbg_printf2 ("snd_pcm_open: mode=0x%x - not emulated.\n", mode); + + if (strcmp (name, "default") == 0) + name = devdsp; + else + { + if (!parse_device (name, dspname)) + { +#if 0 + fprintf (stderr, "OSS asound - Bad PCM device '%s'\n", name); + return -ENOENT; +#else + strcpy (dspname, devdsp); +#endif + } + + name = dspname; + } + + if ((pcm = malloc (sizeof (*pcm))) == NULL) + return -ENOMEM; + + switch (stream) + { + case SND_PCM_STREAM_CAPTURE: + oss_mode = O_RDONLY; + break; + case SND_PCM_STREAM_PLAYBACK: + oss_mode = O_WRONLY; + break; + default: + fprintf (stderr, "snd_pcm_open: Bad stream %d\n", stream); + return -EINVAL; + } + + memset (pcm, 0, sizeof (*pcm)); + pcm->stream = stream; + pcm->frame_size = 2; + pcm->sample_size = 1; + pcm->channels = 2; + pcm->oss_mode = oss_mode; + pcm->state = SND_PCM_STATE_OPEN; + pcm->period_size = PERIOD_SIZE; + pcm->periods = 4; + + if ((pcm->fd = open (name, oss_mode, 0)) == -1) + { + int err = errno; + free (pcm); + return -err; + } + + pcm->info.dev = -1; + if (ioctl (pcm->fd, SNDCTL_ENGINEINFO, &pcm->info) == -1) + { + int err = errno; + close (pcm->fd); + free (pcm); + return -err; + } + + dbg_printf ("Opened %s='%s' = %d\n", name, pcm->info.name, pcm->fd); + *pcmp = pcm; + return 0; +} + +/** + * \brief close PCM handle + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified PCM handle and frees all associated + * resources. + */ +int +snd_pcm_close (snd_pcm_t * pcm) +{ + if (pcm == NULL) + return -1; + close (pcm->fd); + if (pcm->area != NULL) + free (pcm->area); + free (pcm); + return 0; +} + +/** + * \brief Convert frames in bytes for a PCM + * \param pcm PCM handle + * \param frames quantity in frames + * \return quantity expressed in bytes + */ +ssize_t +snd_pcm_frames_to_bytes (snd_pcm_t * pcm, snd_pcm_sframes_t frames) +{ +// printf("snd_pcm_frames_to_bytes(%d)\n", frames); + return frames * pcm->frame_size; +} + +/** + * \brief Convert bytes in frames for a PCM + * \param pcm PCM handle + * \param bytes quantity in bytes + * \return quantity expressed in frames + */ +snd_pcm_sframes_t +snd_pcm_bytes_to_frames (snd_pcm_t * pcm, ssize_t bytes) +{ + dbg_printf3 ("snd_pcm_bytes_to_frames(%d)=%d\n", bytes, + bytes / pcm->frame_size); + return bytes / pcm->frame_size; +} + +/** + * \brief Stop a PCM preserving pending frames + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * \retval -ESTRPIPE a suspend event occurred + * + * For playback wait for all pending frames to be played and then stop + * the PCM. + * For capture stop PCM permitting to retrieve residual frames. + * + * For stopping the PCM stream immediately, use \link ::snd_pcm_drop() \endlink + * instead. + */ +int +snd_pcm_drain (snd_pcm_t * pcm) +{ + dbg_printf2 ("snd_pcm_drain()\n"); + ioctl (pcm->fd, SNDCTL_DSP_SYNC, NULL); + return 0; +} + +/** + * \brief Stop a PCM dropping pending frames + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * This function stops the PCM <i>immediately</i>. + * The pending samples on the buffer are ignored. + * + * For processing all pending samples, use \link ::snd_pcm_drain() \endlink + * instead. + */ +int +snd_pcm_drop (snd_pcm_t * pcm) +{ + dbg_printf2 ("snd_pcm_drop()\n"); + ioctl (pcm->fd, SNDCTL_DSP_HALT, NULL); + return 0; +} + +/** \brief Install one PCM hardware configuration chosen from a configuration sp +ace and #snd_pcm_prepare it + * \param pcm PCM handle + * \param params Configuration space definition container + * \return 0 on success otherwise a negative error code + * + * The configuration is chosen fixing single parameters in this order: + * first access, first format, first subformat, min channels, min rate, + * min period time, max buffer size, min tick time + * + * After this call, #snd_pcm_prepare() is called automatically and + * the stream is brought to \c #SND_PCM_STATE_PREPARED state. + */ +int +snd_pcm_hw_params (snd_pcm_t * pcm, snd_pcm_hw_params_t * params) +{ + int tmp; + + dbg_printf ("snd_pcm_hw_params(%d, %d ch, %x)\n", + params->speed, params->channels, params->oss_fmt); + + tmp = params->oss_fmt; + if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, &tmp) == -1) + return -errno; + if (tmp != params->oss_fmt) + return -EINVAL; + + tmp = params->channels; + if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) + return -errno; + if (tmp != params->channels) + return -EINVAL; + pcm->channels = tmp; + + tmp = params->speed; + if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, &tmp) == -1) + return -errno; + if (tmp != params->speed) + return -EINVAL; + + tmp = params->channels * params->sample_bits; + pcm->frame_size = params->frame_size = tmp / 8; + pcm->sample_size = pcm->frame_size / pcm->channels; + dbg_printf ("Frame size = %d\n", params->frame_size); + return 0; +} + + +/** + * \brief Fill params with a full configuration space for a PCM + * \param pcm PCM handle + * \param params Configuration space + */ +int +snd_pcm_hw_params_any (snd_pcm_t * pcm, snd_pcm_hw_params_t * params) +{ + dbg_printf ("snd_pcm_hw_params_any()\n"); + + memset (params, 0, sizeof (params)); + if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, ¶ms->channels) == -1) + return -errno; + pcm->channels = params->channels; + if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, ¶ms->oss_fmt) == -1) + return -errno; + if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, ¶ms->speed) == -1) + return -errno; + dbg_printf ("Rate %d, channels %d, fmt %x\n", params->speed, + params->channels, params->oss_fmt); + +// TODO + params->frame_size = 2 * params->channels; + params->sample_bits = 16; + + params->info = &pcm->info; + params->pcm = pcm; + return 0; +} + +/** + * \brief Restrict a configuration space to contain only one access type + * \param pcm PCM handle + * \param params Configuration space + * \param access access type + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int +snd_pcm_hw_params_set_access (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + snd_pcm_access_t access) +{ + dbg_printf2 ("snd_pcm_hw_params_set_access(%x/%s)\n", access, + snd_pcm_access_names[access]); + params->access = access; + if (access == SND_PCM_ACCESS_RW_INTERLEAVED) + return 0; + if (access == SND_PCM_ACCESS_MMAP_INTERLEAVED) + return 0; + return -EINVAL; +} + +/** + * \brief Restrict a configuration space to contain only one buffer size + * \param pcm PCM handle + * \param params Configuration space + * \param val buffer size in frames + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int +snd_pcm_hw_params_set_buffer_size (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_hw_params_set_buffer_size()\n"); + + return 0; +} + +int +snd_pcm_hw_params_set_buffer_size_min (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val) +{ + dbg_printf ("snd_pcm_hw_params_set_buffer_size_min()\n"); + + return 0; +} + +/** + * \brief Restrict a configuration space to have buffer size nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target buffer size in frames / returned chosen approxi +mate target buffer size in frames + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int +__snd_pcm_hw_params_set_buffer_size_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val) +{ + dbg_printf ("snd_pcm_hw_params_set_buffer_size_near(%d)\n", *val); + return 0; +} + +/** + * \brief Restrict a configuration space to contain only one channels count + * \param pcm PCM handle + * \param params Configuration space + * \param val channels count + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int +snd_pcm_hw_params_set_channels (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + unsigned int val) +{ + dbg_printf2 ("snd_pcm_hw_params_set_channels(%d)\n", val); + + params->channels = val; + + if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, ¶ms->channels) < 0) + return -errno; + + if (params->channels != val) + return -EINVAL; + pcm->channels = params->channels; + return 0; +} + +int +__snd_pcm_hw_params_set_channels_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val) +{ + dbg_printf2 ("snd_pcm_hw_params_set_channels_near(%d)\n", *val); + + params->channels = *val; + + if (ioctl (pcm->fd, SNDCTL_DSP_CHANNELS, ¶ms->channels) < 0) + return -errno; + + *val = params->channels; + pcm->channels = params->channels; + return 0; +} + +/** + * \brief Restrict a configuration space to contain only one format + * \param pcm PCM handle + * \param params Configuration space + * \param format format + * \return 0 otherwise a negative error code + */ +int +snd_pcm_hw_params_set_format (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + snd_pcm_format_t format) +{ + int err = -EINVAL; + int tmp; + + dbg_printf2 ("snd_pcm_hw_params_set_format(%d)\n", format); + if (format == SND_PCM_FORMAT_U8) + { + params->fmt = format; + params->oss_fmt = AFMT_U8; + params->sample_bits = 8; + err = 0; + } + + if (format == SND_PCM_FORMAT_S16_LE) + { + params->fmt = format; + params->oss_fmt = AFMT_S16_LE; + params->sample_bits = 16; + err = 0; + } + + if (err < 0) + return err; + + tmp = params->oss_fmt; + if (ioctl (pcm->fd, SNDCTL_DSP_SETFMT, &tmp) < 0) + return -errno; + + if (tmp != params->oss_fmt) + return -EINVAL; + + return 0; +} + +/** + * \brief Extract format from a configuration space + * \param params Configuration space + * \param format returned format + * \return format otherwise a negative error code if not exactly one is present + */ +int INTERNAL (snd_pcm_hw_params_get_format) (const snd_pcm_hw_params_t * + params, + snd_pcm_format_t * format) +{ + dbg_printf ("snd_pcm_hw_params_get_format(params=%x)\n", params); + + *format = params->fmt; +} + +/** + * \brief Verify if a format is available inside a configuration space for a PCM * \param pcm PCM handle + * \param params Configuration space + * \param format format + * \return 0 if available a negative error code otherwise + */ +int +snd_pcm_hw_params_test_format (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + snd_pcm_format_t format) +{ + dbg_printf2 ("snd_pcm_hw_params_test_format()\n"); + + if (format == SND_PCM_FORMAT_U8) + return 0; + if (format == SND_PCM_FORMAT_S16_LE) + return 0; + + return -EINVAL; +} + +/** + * \brief Restrict a configuration space to contain only one periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int +snd_pcm_hw_params_set_periods (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + unsigned int val, int dir) +{ + dbg_printf + ("snd_pcm_hw_params_set_periods(pcm=%x, params=%x, val=%d, dir=%d)\n", + pcm, params, val, dir); + pcm->periods = val; + + return 0; +} + +/** + * \brief Restrict a configuration space to contain only integer periods counts + * \param pcm PCM handle + * \param params Configuration space + * \return 0 otherwise a negative error code if configuration space would become empty + */ +int +snd_pcm_hw_params_set_periods_integer (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params) +{ + dbg_printf ("snd_pcm_hw_params_set_periods_integer()\n"); + return 0; +} + +/** * \brief Restrict a configuration space with a minimum periods count + * \param pcm PCM handle * \param params Configuration space + * \param val approximate minimum periods per buffer (on return filled with actual minimum) + * \param dir Sub unit direction (on return filled with actual direction) * \return 0 otherwise a negative error code if configuration space would become + empty * + * Wanted/actual exact minimum is <,=,> val following dir (-1,0,1) */ +int +snd_pcm_hw_params_set_periods_min (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_set_periods_min(%x, %x)\n", val, dir); + return 0; +} + +/** + * \brief Restrict a configuration space with a maximum periods count + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate maximum periods per buffer (on return filled with actual maximum) + * \param dir Sub unit direction (on return filled with actual direction) + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted/actual exact maximum is <,=,> val following dir (-1,0,1) + */ +int +snd_pcm_hw_params_set_periods_max (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_set_periods_max(%x, %x)\n", val, dir); + return 0; + return -EINVAL; +} + +/** + * \brief Restrict a configuration space to contain only one rate + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int +snd_pcm_hw_params_set_rate (snd_pcm_t * pcm, snd_pcm_hw_params_t * params, + unsigned int val, int dir) +{ + dbg_printf2 ("snd_pcm_hw_params_set_rate(%d, %d)\n", val, dir); + + params->speed = val; + + if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, ¶ms->speed) < 0) + return -errno; + + if (val != params->speed) + return -EINVAL; + + return 0; +} + +/** + * \brief Extract rate from a configuration space + * \param params Configuration space + * \param val Returned approximate rate + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +int INTERNAL (snd_pcm_hw_params_get_rate) (const snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_rate(params=%x)=%d\n", + params, params->speed); + + *val = params->speed; + *dir = 0; + return 0; +} + +/** + * \brief Restrict a configuration space to have rate nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target rate / returned approximate set rate + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int +__snd_pcm_hw_params_set_rate_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + dbg_printf2 ("snd_pcm_hw_params_set_rate_near(%d)\n", *val); + + params->speed = *val; + + if (ioctl (pcm->fd, SNDCTL_DSP_SPEED, ¶ms->speed) < 0) + return -errno; + + *val = params->speed; + return 0; +} + +/** + * \brief get size of #snd_pcm_hw_params_t + * \return size in bytes + */ +size_t +snd_pcm_hw_params_sizeof () +{ + return sizeof (snd_pcm_hw_params_t); +} + +/** + * \brief set nonblock mode + * \param pcm PCM handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_nonblock (snd_pcm_t * pcm, int nonblock) +{ + dbg_printf2 ("snd_pcm_nonblock(%d)\n", nonblock); + + if (nonblock == 0) + return 0; + + return -EINVAL; +} + +/** + * \brief Prepare PCM for use + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_prepare (snd_pcm_t * pcm) +{ + dbg_printf2 ("snd_pcm_prepare()\n"); + return 0; +} + +/** + * \brief Read interleaved frames from a PCM + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SN +D_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting f +or an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_readi (snd_pcm_t * pcm, void *buffer, snd_pcm_uframes_t size) +{ + int l; + + dbg_printf3 ("snd_pcm_readi(%d)\n", pcm->fd); + + pcm->state = SND_PCM_STATE_RUNNING; + + l = size * pcm->frame_size; + + if ((l = read (pcm->fd, buffer, l)) == -1) + return -errno; + return l / pcm->frame_size; +} + +/** \brief Remove PCM hardware configuration and free associated resources + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_hw_free (snd_pcm_t * pcm) +{ + dbg_printf ("snd_pcm_hw_free()\n"); + + return 0; +} + +/** + * \brief Remove a PCM from a linked group + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_unlink (snd_pcm_t * pcm) +{ + dbg_printf ("snd_pcm_unlink()\n"); + + return 0; +} + +/** + * \brief Extract tick time from a configuration space + * \param params Configuration space + * \param val Returned approximate tick duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +int INTERNAL (snd_pcm_hw_params_get_tick_time) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_tick_time()\n"); + + *val = 1; + *dir = 0; + return 0; +} + +/** + * \brief Write interleaved frames to a PCM + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SN +D_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting f +or an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_writei (snd_pcm_t * pcm, const void *buffer, snd_pcm_uframes_t size) +{ + int l; + + dbg_printf3 ("snd_pcm_writei(%d)\n", size); + + pcm->state = SND_PCM_STATE_RUNNING; + + l = size * pcm->frame_size; + + if ((l = write (pcm->fd, buffer, l)) == -1) + return -errno; + return l / pcm->frame_size; +} + +/** + * \brief Resume from suspend, no samples are lost + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * \retval -EAGAIN resume can't be proceed immediately (audio hardware is probab +ly still suspended) + * \retval -ENOSYS hardware doesn't support this feature + * + * This function can be used when the stream is in the suspend state + * to do the fine resume from this state. Not all hardware supports + * this feature, when an -ENOSYS error is returned, use the \link ::snd_pcm_prep +are() \endlink + * function to recovery. + */ +int +snd_pcm_resume (snd_pcm_t * pcm) +{ + dbg_printf ("snd_pcm_resume()\n"); + return -EINVAL; +} + +/** + * \brief allocate an invalid #snd_pcm_status_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_pcm_status_malloc (snd_pcm_status_t ** ptr) +{ + assert (ptr); + *ptr = calloc (1, sizeof (snd_pcm_status_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_status_t + * \param pointer to object to free + */ +void +snd_pcm_status_free (snd_pcm_status_t * obj) +{ + free (obj); +} + + +/** + * \brief Obtain status (runtime) information for PCM handle + * \param pcm PCM handle + * \param status Status container + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_status (snd_pcm_t * pcm, snd_pcm_status_t * status) +{ + dbg_printf ("snd_pcm_status()\n"); + return -EINVAL; +} + +/** + * \brief Get state from a PCM status container (see #snd_pcm_state) + * \return PCM state + */ +snd_pcm_state_t +snd_pcm_status_get_state (const snd_pcm_status_t * obj) +{ + dbg_printf ("snd_pcm_status_get_state()\n"); + return -EINVAL; +} + +/** + * \brief Get number of frames available from a PCM status container (see #snd_pcm_avail_update) + * \return Number of frames ready to be read/written + */ +snd_pcm_uframes_t +snd_pcm_status_get_avail (const snd_pcm_status_t * obj) +{ + dbg_printf ("snd_pcm_status_get_avail()\n"); + + return 1; +} + +/** + * \brief get size of #snd_pcm_status_t + * \return size in bytes + */ +size_t +snd_pcm_status_sizeof () +{ + return sizeof (snd_pcm_status_t); +} + +/** + * \brief Dump PCM info + * \param pcm PCM handle + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_dump (snd_pcm_t * pcm, snd_output_t * out) +{ + dbg_printf ("snd_pcm_dump()\n"); + return 0; +} + +void +snd_pcm_hw_params_copy (snd_pcm_hw_params_t * dst, + const snd_pcm_hw_params_t * src) +{ + memcpy (dst, src, sizeof (*dst)); +} + +void +snd_pcm_hw_params_free (snd_pcm_hw_params_t * p) +{ + free (p); +} + +int +snd_pcm_hw_params_can_mmap_sample_resolution (const snd_pcm_hw_params_t * + params) +{ + return 0; +} + +int +snd_pcm_hw_params_can_overrange (const snd_pcm_hw_params_t * params) +{ + return 0; +} + +int +snd_pcm_hw_params_can_pause (const snd_pcm_hw_params_t * params) +{ + return 0; +} + +int +snd_pcm_hw_params_can_resume (const snd_pcm_hw_params_t * params) +{ + return 0; +} + +int +snd_pcm_hw_params_can_sync_start (const snd_pcm_hw_params_t * params) +{ + return 1; +} + +int +snd_pcm_hw_params_get_channels (const snd_pcm_hw_params_t * params, + unsigned int *val) +{ + *val = params->channels; + return 0; +} + +int INTERNAL (snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t * + params, unsigned int *val) +{ + *val = params->info->min_channels; + return 0; +} + +int INTERNAL (snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t * + params, unsigned int *val) +{ + *val = params->info->max_channels; + return 0; +} + +int INTERNAL (snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + *val = params->info->min_rate; + return 0; +} + +int INTERNAL (snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + *val = params->info->max_rate; + return 0; +} + +// int snd_pcm_hw_params_get_(const snd_pcm_hw_params_t *params, unsigned int *val) { return 0;} + +/** + * \brief get name of PCM sample format + * \param format PCM sample format + * \return ascii name of PCM sample format + */ +const char * +snd_pcm_format_name (snd_pcm_format_t format) +{ + if (format > SND_PCM_FORMAT_LAST) + return NULL; + return snd_pcm_format_names[format]; +} + +/** + * \brief Return PCM state + * \param pcm PCM handle + * \return PCM state #snd_pcm_state_t of given PCM handle + * + * This is a faster way to obtain only the PCM state without calling + * \link ::snd_pcm_status() \endlink. + */ +snd_pcm_state_t +snd_pcm_state (snd_pcm_t * pcm) +{ + dbg_printf3 ("snd_pcm_state()\n"); + return pcm->state; +} + +/** + * \brief allocate an invalid #snd_pcm_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_pcm_info_malloc (snd_pcm_info_t ** ptr) +{ + assert (ptr); + *ptr = calloc (1, sizeof (snd_pcm_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_info_t + * \param pointer to object to free + */ +void +snd_pcm_info_free (snd_pcm_info_t * obj) +{ + free (obj); +} + + +/** + * \brief Obtain general (static) information for PCM handle + * \param pcm PCM handle + * \param info Information container + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_info (snd_pcm_t * pcm, snd_pcm_info_t * info) +{ + dbg_printf ("snd_pcm_info()\n"); + memset (info, 0, sizeof (*info)); + info->ainfo = &pcm->info; + + return 0; +} + +/** + * \brief Get card from a PCM info container + * \param obj PCM info container + * \return card number otherwise a negative error code if not associable to a card + */ +int +snd_pcm_info_get_card (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_card()\n"); + return obj->ainfo->card_number; +} + +/** + * \brief Get device from a PCM info container + * \param obj PCM info container + * \return device number + */ +unsigned int +snd_pcm_info_get_device (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_device()\n"); + return obj->ainfo->dev; +} + +/** + * \brief Get name from a PCM info container + * \param obj PCM info container + * \return name of PCM + */ +const char * +snd_pcm_info_get_name (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_name()\n"); + + return obj->ainfo->name; +} + +/** + * \brief Get subdevice from a PCM info container + * \param obj PCM info container + * \return subdevice number + */ +unsigned int +snd_pcm_info_get_subdevice (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_subdevice()\n"); + return 0; +} + +/** + * \brief Set wanted device inside a PCM info container (see #snd_ctl_pcm_info) + * \param obj PCM info container + * \param val Device number + */ +void +snd_pcm_info_set_device (snd_pcm_info_t * obj, unsigned int val) +{ + dbg_printf ("snd_pcm_info_set_device()\n"); +} + +/** + * \brief Set wanted subdevice inside a PCM info container (see #snd_ctl_pcm_info) + * \param obj PCM info container + * \param val Subdevice number + */ +void +snd_pcm_info_set_subdevice (snd_pcm_info_t * obj, unsigned int val) +{ + dbg_printf ("snd_pcm_info_set_subdevice()\n"); +} + +void +snd_pcm_info_set_stream (snd_pcm_info_t * obj, snd_pcm_stream_t val) +{ + dbg_printf ("snd_pcm_info_set_stream()\n"); +} + +/** + * \brief get size of #snd_pcm_info_t + * \return size in bytes + */ +size_t +snd_pcm_info_sizeof () +{ + return sizeof (snd_pcm_info_t); +} + + +/** + * \brief Return number of frames ready to be read/written + * \param pcm PCM handle + * \return a positive number of frames ready otherwise a negative + * error code + * + * On capture does all the actions needed to transport to application + * level all the ready frames across underlying layers. + * + * Using of this function is useless for the standard read/write + * operations. Use it only for mmap access. See to #snd_pcm_delay. + */ +snd_pcm_sframes_t +snd_pcm_avail_update (snd_pcm_t * pcm) +{ + audio_buf_info bi; + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + { + if (ioctl (pcm->fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) + return -errno; + } + else + { + if (ioctl (pcm->fd, SNDCTL_DSP_GETISPACE, &bi) == -1) + return -errno; + } + + dbg_printf3 ("snd_pcm_avail_update(pcm=%x)=%d\n", pcm, + bi.bytes / pcm->frame_size); + return bi.bytes / pcm->frame_size; +} + +/** + * \brief Obtain delay for a running PCM handle + * \param pcm PCM handle + * \param delayp Returned delay in frames + * \return 0 on success otherwise a negative error code + * + * Delay is distance between current application frame position and + * sound frame position. + * It's positive and less than buffer size in normal situation, + * negative on playback underrun and greater than buffer size on + * capture overrun. + * + * Note this function does not update the actual r/w pointer + * for applications. The function #snd_pcm_avail_update() + * have to be called before any begin+commit operation. + */ +int +snd_pcm_delay (snd_pcm_t * pcm, snd_pcm_sframes_t * delayp) +{ + int tmp; + + if (ioctl (pcm->fd, SNDCTL_DSP_GETODELAY, &tmp) < 0) + return -errno; + + *delayp = tmp / pcm->frame_size; + return 0; +} + +/** + * \brief Return bits needed to store a PCM sample + * \param format Sample format + * \return bits per sample, a negative error code if not applicable + */ +int +snd_pcm_format_physical_width (snd_pcm_format_t format) +{ + switch (format) + { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return 24; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return 64; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return 8; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + return 4; + default: + return -EINVAL; + } +} + +/** + * \brief Return bytes needed to store a quantity of PCM sample + * \param format Sample format + * \param samples Samples count + * \return bytes needed, a negative error code if not integer or unknown + */ +ssize_t +snd_pcm_format_size (snd_pcm_format_t format, size_t samples) +{ + switch (format) + { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return samples; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return samples * 2; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return samples * 3; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + return samples * 4; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return samples * 8; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return samples * 4; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return samples; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + if (samples & 1) + return -EINVAL; + return samples / 2; + default: + assert (0); + return -EINVAL; + } +} + +/** + * \brief Dump a PCM hardware configuration space + * \param params Configuration space + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_hw_params_dump (snd_pcm_hw_params_t * params, snd_output_t * out) +{ + return 0; +} + +/** + * \brief Extract buffer size from a configuration space + * \param params Configuration space + * \param val Returned buffer size in frames + * \return 0 otherwise a negative error code if not exactly one is present + */ +int +__snd_pcm_hw_params_get_buffer_size (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val) +{ + *val = 65536; + + return 0; +} + +int +snd_pcm_hw_params_get_buffer_size_min (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val) +{ + *val = 65536; + + return 0; +} + +int +snd_pcm_hw_params_get_buffer_size_max (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val) +{ + *val = 65536; + + return 0; +} + +/** + * \brief Extract access type from a configuration space + * \param params Configuration space + * \param access Returned value + * \return access type otherwise a negative error code if not exactly one is present + */ +int INTERNAL (snd_pcm_hw_params_get_access) (const snd_pcm_hw_params_t * + params, + snd_pcm_access_t * access) +{ + dbg_printf ("snd_pcm_hw_params_get_access()\n"), *access = params->access; + + return 0; +} + +/** + * \brief Extract period size from a configuration space + * \param params Configuration space + * \param val Returned approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +int +__snd_pcm_hw_params_get_period_size (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_period_size(params=%x)=%d\n", + params, params->pcm->period_size); + *val = params->pcm->period_size; + if (dir) *dir = 0; + return 0; +} + +int +snd_pcm_hw_params_get_period_size_min (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_period_size_min(params=%x)=%d\n", + params, params->pcm->period_size); + *val = params->pcm->period_size; + if (dir) *dir = 0; + return 0; +} + +int +snd_pcm_hw_params_get_period_size_max (const snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val, int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_period_size_min(params=%x)=%d\n", + params, params->pcm->period_size); + *val = params->pcm->period_size; + if (dir) *dir = 0; + return 0; +} + +/** + * \brief Extract periods from a configuration space + * \param params Configuration space + * \param val approximate periods per buffer + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +int INTERNAL (snd_pcm_hw_params_get_periods) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_periods(params=%x)=%d\n", + params, params->pcm->periods); + + *val = params->pcm->periods; + + return 0; +} + +/** + * \brief Restrict a configuration space to have period size nearest to a target * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target period size in frames / returned chosen approximate target period size + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int +__snd_pcm_hw_params_set_period_size_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_uframes_t * val, int *dir) +{ + dbg_printf + ("snd_pcm_hw_params_set_period_size_near(pcm=%x, params=%x, val=%d, dir=%d)\n", + pcm, params, *val, dir?*dir:-1); + pcm->period_size = *val; + return 0; +} + +/** + * \brief Restrict a configuration space to have buffer time nearest to a target * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int +__snd_pcm_hw_params_set_period_time_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + dbg_printf2 ("snd_pcm_hw_params_set_period_time_near()\n"); + return 0; +} + +/** + * \brief Application request to access a portion of direct (mmap) area + * \param pcm PCM handle + * \param areas Returned mmap channel areas + * \param offset Returned mmap area offset in area steps (== frames) + * \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit) + * \return 0 on success otherwise a negative error code + * + * It is necessary to call the snd_pcm_avail_update() function directly before + * this call. Otherwise, this function can return a wrong count of available frames. + * + * The function should be called before a sample-direct area can be accessed. + * The resulting size parameter is always less or equal to the input count of frames + * and can be zero, if no frames can be processed (the ring buffer is full). + * + * See the snd_pcm_mmap_commit() function to finish the frame processing in + * the direct areas. + */ +int +snd_pcm_mmap_begin (snd_pcm_t * pcm, + const snd_pcm_channel_area_t ** areas, + snd_pcm_uframes_t * offset, snd_pcm_uframes_t * frames) +{ + dbg_printf2 ("snd_pcm_mmap_begin(frames=%d)\n", *frames); + if (pcm->area == NULL) + { + pcm->area = malloc (sizeof (*pcm->area) * pcm->channels); + pcm->area[0].addr = malloc (65536); + pcm->area[0].first = 0; + pcm->area[0].step = pcm->frame_size * 8; + pcm->area[1].addr = pcm->area[0].addr + pcm->sample_size; + pcm->area[1].first = 0; + pcm->area[1].step = pcm->frame_size * 8; + } + + *areas = pcm->area; + *offset = 0; + if (*frames * pcm->frame_size > 65536) + *frames = 65536 / pcm->frame_size; + return 0; +} + +/** + * \brief Application has completed the access to area requested with #snd_pcm_mmap_begin + * \param pcm PCM handle + * \param offset area offset in area steps (== frames) + * \param size area portion size in frames + * \return count of transferred frames otherwise a negative error code + * + * You should pass this function the offset value that + * snd_pcm_mmap_begin() returned. The frames parameter should hold the + * number of frames you have written or read to/from the audio + * buffer. The frames parameter must never exceed the contiguous frames + * count that snd_pcm_mmap_begin() returned. Each call to snd_pcm_mmap_begin() + * must be followed by a call to snd_pcm_mmap_commit(). + * + * Example: +\code + double phase = 0; + const snd_pcm_area_t *areas; + snd_pcm_sframes_t avail, size, commitres; + snd_pcm_uframes_t offset, frames; + int err; + + avail = snd_pcm_avail_update(pcm); + if (avail < 0) + error(avail); + // at this point, we can transfer at least 'avail' frames + + // we want to process frames in chunks (period_size) + if (avail < period_size) + goto _skip; + size = period_size; + // it is possible that contiguous areas are smaller, thus we use a loop + while (size > 0) { + frames = size; + + err = snd_pcm_mmap_begin(pcm_handle, &areas, &offset, &frames); + if (err < 0) + error(err); + // this function fills the areas from offset with count of frames + generate_sine(areas, offset, frames, &phase); + commitres = snd_pcm_mmap_commit(pcm_handle, offset, frames); + if (commitres < 0 || commitres != frames) + error(commitres >= 0 ? -EPIPE : commitres); + + size -= frames; + } + _skip: +\endcode + * + * Look to the \ref example_test_pcm "Sine-wave generator" example + * for more details about the generate_sine function. + */ +snd_pcm_sframes_t +snd_pcm_mmap_commit (snd_pcm_t * pcm, + snd_pcm_uframes_t offset, snd_pcm_uframes_t frames) +{ + dbg_printf2 ("snd_pcm_mmap_commit(frames=%d, offs=%d)\n", frames, offset); + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + return snd_pcm_writei (pcm, pcm->area[0].addr, frames); + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + return snd_pcm_readi (pcm, pcm->area[0].addr, frames); + + return -EFAULT; +} + +/** + * \brief Restrict a configuration space to have buffer time nearest to a target * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target buffer duration in us / returned chosen approximate target buffer duration + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int +__snd_pcm_hw_params_set_buffer_time_near (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + unsigned int *val, int *dir) +{ + *val = 10; + dbg_printf2 ("snd_pcm_hw_params_set_buffer_time_near()\n"); + return 0; +} + +/** + * \brief Pause/resume PCM + * \param pcm PCM handle + * \param pause 0 = resume, 1 = pause + * \return 0 on success otherwise a negative error code + * + * Note that this function works only on the hardware which supports + * pause feature. You can check it via \link ::snd_pcm_hw_params_can_pause() \endlink + * function. + */ +int +snd_pcm_pause (snd_pcm_t * pcm, int enable) +{ + dbg_printf ("snd_pcm_pause()\n"); + return -EINVAL; +} + +/** + * \brief Start a PCM + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_start (snd_pcm_t * pcm) +{ + dbg_printf ("snd_pcm_start()\n"); + return 0; +} + +/** + * \brief Convert samples in bytes for a PCM + * \param pcm PCM handle + * \param samples quantity in samples + * \return quantity expressed in bytes + */ +ssize_t +snd_pcm_samples_to_bytes (snd_pcm_t * pcm, long samples) +{ + dbg_printf2 ("snd_pcm_samples_to_bytes(%d)=%d\n", samples, + samples * pcm->sample_size); + return samples * pcm->sample_size; +} + + +/** + * \brief Dump status + * \param status Status container + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_status_dump (snd_pcm_status_t * status, snd_output_t * out) +{ + return 0; +} + +/** \brief Install PCM software configuration defined by params + * \param pcm PCM handle + * \param params Configuration container + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_sw_params (snd_pcm_t * pcm, snd_pcm_sw_params_t * params) +{ + dbg_printf2 ("snd_pcm_sw_params()\n"); + // NOP + return 0; +} + +/** + * \brief Return current software configuration for a PCM + * \param pcm PCM handle + * \param params Software configuration container + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_sw_params_current (snd_pcm_t * pcm, snd_pcm_sw_params_t * params) +{ + dbg_printf2 ("snd_pcm_sw_params_current()\n"); + // NOP + return 0; +} + +/** + * \brief Dump a software configuration + * \param params Software configuration container + * \param out Output handle + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_sw_params_dump (snd_pcm_sw_params_t * params, snd_output_t * out) +{ + return 0; +} + +/** + * \brief Set start threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Start threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically started when playback frames available to PCM + * are >= threshold or when requested capture frames are >= threshold + */ +int +snd_pcm_sw_params_set_start_threshold (snd_pcm_t * pcm, + snd_pcm_sw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf2 ("snd_pcm_sw_params_set_start_threshold(%d)\n", val); + // NOP + return 0; +} + +/** + * \brief get size of #snd_pcm_sw_params_t + * \return size in bytes + */ +size_t +snd_pcm_sw_params_sizeof () +{ + return sizeof (snd_pcm_sw_params_t); +} + +/** + * \brief Restrict a configuration space to have periods count nearest to a target + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate target periods per buffer / returned chosen approximate target periods per buffer + * \return 0 otherwise a negative error code if configuration space is empty + * + * target/chosen exact value is <,=,> val following dir (-1,0,1) + */ +int INTERNAL (snd_pcm_hw_params_set_periods_near) (snd_pcm_t * pcm, + snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + dbg_printf + ("snd_pcm_hw_params_set_periods_near(pcm=%x, params=%x, val=%d, dir=%d)\n"); + pcm->periods = *val; + return 0; +} + +/** + * \brief get poll descriptors + * \param pcm PCM handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + * + * This function fills the given poll descriptor structs for the specified + * PCM handle. The poll desctiptor array should have the size returned by + * \link ::snd_pcm_poll_descriptors_count() \endlink function. + * + * The result is intended for direct use with the poll() syscall. + * + * For reading the returned events of poll descriptor after poll() system + * call, use \link ::snd_pcm_poll_descriptors_revents() \endlink function. + * The field values in pollfd structs may be bogus regarding the stream + * direction from the application perspective (POLLIN might not imply read + * direction and POLLOUT might not imply write), but + * the \link ::snd_pcm_poll_descriptors_revents() \endlink function + * does the right "demangling". + * + * You can use output from this function as arguments for the select() + * syscall, too. + */ +int +snd_pcm_poll_descriptors (snd_pcm_t * pcm, struct pollfd *pfds, + unsigned int space) +{ + dbg_printf2 ("snd_pcm_poll_descriptors(pcm=%x)\n", pcm); + + pfds->fd = pcm->fd; + pfds->events = 0; + pfds->revents = 0; + + if (pcm->oss_mode == O_WRONLY || pcm->oss_mode == O_RDWR) + pfds->events = POLLOUT; + if (pcm->oss_mode == O_RDONLY || pcm->oss_mode == O_RDWR) + pfds->events = POLLIN; + + return 1; +} + +/** + * \brief get count of poll descriptors for PCM handle + * \param pcm PCM handle + * \return count of poll descriptors + */ +int +snd_pcm_poll_descriptors_count (snd_pcm_t * pcm) +{ + dbg_printf ("snd_pcm_poll_descriptors_count()\n"); + + return 1; +} + +/** + * \brief get returned events from poll descriptors + * \param pcm PCM handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + * + * This function does "demangling" of the revents mask returned from + * the poll() syscall to correct semantics (POLLIN = read, POLLOUT = write). + * + * Note: The null event also exists. Even if poll() or select() + * syscall returned that some events are waiting, this function might + * return empty set of events. In this case, application should + * do next event waiting using poll() or select(). + */ +int +snd_pcm_poll_descriptors_revents (snd_pcm_t * pcm, struct pollfd *pfds, + unsigned int nfds, unsigned short *revents) +{ + dbg_printf3 ("snd_pcm_poll_descriptors_revents()\n"); + + *revents = pfds->revents; + return 0; +} + +/** + * \brief allocate an invalid #snd_pcm_hw_params_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_pcm_hw_params_malloc (snd_pcm_hw_params_t ** ptr) +{ + *ptr = calloc (1, sizeof (snd_pcm_hw_params_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_pcm_sw_params_t + * \param pointer to object to free + */ +void +snd_pcm_sw_params_free (snd_pcm_sw_params_t * obj) +{ + free (obj); +} + +/** + * \brief Write non interleaved frames to a PCM + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_writen (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_writen()\n"); + // Not supported + return -EINVAL; +} + +/** + * \brief Read non interleaved frames to a PCM + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_readn (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_readn()\n"); + // Not supported + return -EINVAL; +} + +/** + * \brief Get trigger timestamp from a PCM status container + * \param ptr Pointer to returned timestamp + */ +void +snd_pcm_status_get_trigger_tstamp (const snd_pcm_status_t * obj, + snd_timestamp_t * ptr) +{ + dbg_printf ("snd_pcm_status_get_trigger_tstamp()\n"); + ptr->tv_sec = 0; + ptr->tv_usec = 0; +} + +/** + * \brief Set xfer align inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Chunk size (frames are attempted to be transferred in chunks) + * \return 0 otherwise a negative error code + */ +int +snd_pcm_sw_params_set_xfer_align (snd_pcm_t * pcm, + snd_pcm_sw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_sw_params_set_xfer_align(%d)\n", val); + // TODO + return 0; +} + +/** + * \brief Get xfer align from a software configuration container + * \param params Software configuration container + * \param val returned chunk size (frames are attempted to be transferred in chunks) + * \param 0 otherwise a negative error code + */ +int INTERNAL (snd_pcm_sw_params_get_xfer_align) (const snd_pcm_sw_params_t * + params, + snd_pcm_uframes_t * val) +{ + dbg_printf ("snd_pcm_sw_params_get_xfer_align()\n"); + + return 8; +} + +/** + * \brief Set avail min inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Minimum avail frames to consider PCM ready + * \return 0 otherwise a negative error code + * + * Note: This is similar to setting an OSS wakeup point. The valid + * values for 'val' are determined by the specific hardware. Most PC + * sound cards can only accept power of 2 frame counts (i.e. 512, + * 1024, 2048). You cannot use this as a high resolution timer - it + * is limited to how often the sound card hardware raises an + * interrupt. Note that you can greatly improve the reponses using + * \ref snd_pcm_sw_params_set_sleep_min where another timing source + * is used. + */ +int +snd_pcm_sw_params_set_avail_min (snd_pcm_t * pcm ATTRIBUTE_UNUSED, + snd_pcm_sw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_sw_params_set_avail_min()\n"); + // NOP + return 0; +} + +/** + * \brief Set minimum number of ticks to sleep inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Minimum ticks to sleep or 0 to disable the use of tick timer + * \return 0 otherwise a negative error code + */ +int +snd_pcm_sw_params_set_sleep_min (snd_pcm_t * pcm ATTRIBUTE_UNUSED, + snd_pcm_sw_params_t * params, + unsigned int val) +{ + dbg_printf ("snd_pcm_sw_params_set_sleep_min()\n"); + // NOP + + return 0; +} + +/** + * \brief Wait for a PCM to become ready + * \param pcm PCM handle + * \param timeout maximum time in milliseconds to wait + * \return a positive value on success otherwise a negative error code + * (-EPIPE for the xrun and -ESTRPIPE for the suspended status, + * others for general errors) + * \retval 0 timeout occurred + * \retval 1 PCM stream is ready for I/O + */ +int +snd_pcm_wait (snd_pcm_t * pcm, int timeout) +{ + fd_set fds, *readfds = NULL, *writefds = NULL; + struct timeval wait, *w = NULL; + + dbg_printf ("snd_pcm_wait(%d)\n", timeout); + + FD_ZERO (&fds); + FD_SET (pcm->fd, &fds); + + if (timeout > 0) + { + wait.tv_sec = timeout / 1000; + wait.tv_usec = (timeout % 1000) * 1000; + w = &wait; + } + + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) + writefds = &fds; + else + readfds = &fds; + + dbg_printf ("select(%d, %x, %x, NULL, %x)\n", + pcm->fd + 1, readfds, writefds, w); + if (select (pcm->fd + 1, readfds, writefds, NULL, w) == -1) + return -errno; + + return FD_ISSET (pcm->fd, &fds); +} + +/** + * \brief allocate an invalid #snd_pcm_sw_params_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_pcm_sw_params_malloc (snd_pcm_sw_params_t ** ptr) +{ + *ptr = calloc (1, sizeof (snd_pcm_sw_params_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief Extract period time from a configuration space + * \param params Configuration space + * \param val Returned approximate period duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if not exactly one is present + * + * Actual exact value is <,=,> the approximate one following dir (-1, 0, 1) + */ +int INTERNAL (snd_pcm_hw_params_get_period_time) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_period_time()\n"); + // TODO + return -EINVAL; +} + +int INTERNAL (snd_pcm_hw_params_get_buffer_time) (const snd_pcm_hw_params_t * + params, unsigned int *val, + int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_buffer_time()\n"); + // What's this? + return -EINVAL; +} + +struct _snd_mask +{ + unsigned int bits[4]; +}; + +struct _snd_pcm_access_mask +{ + unsigned int bits[4]; +}; + +#define MASK_OFS(v) (v/32) +#define MASK_BIT(v) (1<<(v%32)) + +/** + * \brief reset all bits in a #snd_pcm_access_mask_t + * \param mask pointer to mask + */ +void +snd_pcm_access_mask_none (snd_pcm_access_mask_t * mask) +{ + dbg_printf ("snd_pcm_access_mask_none()\n"); + memset (mask, 0, sizeof (*mask)); +} + +/** + * \brief make an access type present in a #snd_pcm_access_mask_t + * \param mask pointer to mask + * \param val access type + */ +void +snd_pcm_access_mask_set (snd_pcm_access_mask_t * mask, snd_pcm_access_t val) +{ + dbg_printf ("snd_pcm_access_mask_t(%d)\n", val); + mask->bits[MASK_OFS (val)] |= MASK_BIT (val); +} + +/** + * \brief get size of #snd_pcm_access_mask_t + * \return size in bytes + */ +size_t +snd_pcm_access_mask_sizeof () +{ + return sizeof (snd_pcm_access_mask_t); +} + +/** + * \brief Restrict a configuration space to contain only a set of access types + * \param pcm PCM handle + * \param params Configuration space + * \param mask Access mask + * \return 0 otherwise a negative error code + */ +int +snd_pcm_hw_params_set_access_mask (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_access_mask_t * mask) +{ + dbg_printf ("snd_pcm_hw_params_set_access_mask()\n"); + // NOP + return 0; +} + +/** + * \brief Read interleaved frames from a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_mmap_readi (snd_pcm_t * pcm, void *buffer, snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_mmap_readi()\n"); + return snd_pcm_readi (pcm, buffer, size); +} + +/** + * \brief Read non interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually read otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an overrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour was selected, then routine waits until + * all requested bytes are filled. The count of bytes can be less only + * if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_mmap_readn (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_mmap_readn()\n"); + return snd_pcm_readn (pcm, bufs, size); +} + +/** + * \brief Write interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param buffer frames containing buffer + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_mmap_writei (snd_pcm_t * pcm, const void *buffer, + snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_mmap_writei()\n"); + + return snd_pcm_writei (pcm, buffer, size); +} + +/** + * \brief Write non interleaved frames to a PCM using direct buffer (mmap) + * \param pcm PCM handle + * \param bufs frames containing buffers (one for each channel) + * \param size frames to be written + * \return a positive number of frames actually written otherwise a + * negative error code + * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) + * \retval -EPIPE an underrun occurred + * \retval -ESTRPIPE a suspend event occurred (stream is suspended and waiting for an application recovery) + * + * If the blocking behaviour is selected, then routine waits until + * all requested bytes are played or put to the playback ring buffer. + * The count of bytes can be less only if a signal or underrun occurred. + * + * If the non-blocking behaviour is selected, then routine doesn't wait at all. + */ +snd_pcm_sframes_t +snd_pcm_mmap_writen (snd_pcm_t * pcm, void **bufs, snd_pcm_uframes_t size) +{ + dbg_printf ("snd_pcm_mmap_writen()\n"); + return snd_pcm_writen (pcm, bufs, size); +} + +/** + * \brief Link two PCMs + * \param pcm1 first PCM handle + * \param pcm2 first PCM handle + * \return 0 on success otherwise a negative error code + * + * The two PCMs will start/stop/prepare in sync. + */ +int +snd_pcm_link (snd_pcm_t * pcm1, snd_pcm_t * pcm2) +{ + dbg_printf ("snd_pcm_link()\n"); + return -EINVAL; +} + +/** + * \brief Set silence size inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Silence size in frames (0 for disabled) + * \return 0 otherwise a negative error code + * + * A portion of playback buffer is overwritten with silence when playback + * underrun is nearer than silence threshold (see + * #snd_pcm_sw_params_set_silence_threshold) + * + * The special case is when silence size value is equal or greater than + * boundary. The unused portion of the ring buffer (initial written samples + * are untouched) is filled with silence at start. Later, only just processed + * sample area is filled with silence. Note: silence_threshold must be set to zero. + */ +int +snd_pcm_sw_params_set_silence_size (snd_pcm_t * pcm, + snd_pcm_sw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_sw_params_set_silence_size()\n"); + + return 0; +} + +/** + * \brief Set silence threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Silence threshold in frames + * \return 0 otherwise a negative error code + * + * A portion of playback buffer is overwritten with silence (see + * #snd_pcm_sw_params_set_silence_size) when playback underrun is nearer + * than silence threshold. + */ +int +snd_pcm_sw_params_set_silence_threshold (snd_pcm_t * pcm, snd_pcm_sw_params_t + * params, snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_sw_params_set_silence_threshold()\n"); + + return 0; +} + +/** + * \brief Restrict a configuration space to contain only one period size + * \param pcm PCM handle + * \param params Configuration space + * \param val approximate period size in frames + * \param dir Sub unit direction + * \return 0 otherwise a negative error code if configuration space would become empty + * + * Wanted exact value is <,=,> val following dir (-1,0,1) + */ +int +snd_pcm_hw_params_set_period_size (snd_pcm_t * pcm, + snd_pcm_hw_params_t * params, + snd_pcm_uframes_t val, int dir) +{ + dbg_printf + ("snd_pcm_hw_params_set_period_size(pcm=%x, params=%x, val=%d, dir=%d)\n", + pcm, params, val, dir); + pcm->period_size = val; + return 0; +} + +/** + * \brief Set stop threshold inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container + * \param val Stop threshold in frames + * \return 0 otherwise a negative error code + * + * PCM is automatically stopped in #SND_PCM_STATE_XRUN state when available + * frames is >= threshold. If the stop threshold is equal to boundary (also + * software parameter - sw_param) then automatic stop will be disabled + * (thus device will do the endless loop in the ring buffer). + */ +int +snd_pcm_sw_params_set_stop_threshold (snd_pcm_t * pcm, + snd_pcm_sw_params_t * params, + snd_pcm_uframes_t val) +{ + dbg_printf ("snd_pcm_sw_params_set_stop_threshold()\n"); + + return 0; +} + +/** + * \brief Return 16 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 16 bit word + */ +u_int16_t +snd_pcm_format_silence_16 (snd_pcm_format_t format) +{ + dbg_printf ("snd_pcm_format_silence_16(%x)\n", format); + return 0; +} + +/** + * \brief Return 8 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 8 bit word + */ +u_int8_t +snd_pcm_format_silence (snd_pcm_format_t format) +{ + + dbg_printf ("snd_pcm_format_silence(%x)\n", format); + + return 0x80; +} + + +/** + * \brief Return 32 bit expressing silence for a PCM sample format + * \param format Sample format + * \return silence 32 bit word + */ +u_int32_t +snd_pcm_format_silence_32 (snd_pcm_format_t format) +{ + dbg_printf ("snd_pcm_format_silence_32(%x)\n", format); + return 0; +} + + +/** + * \brief Get available subdevices count from a PCM info container + * \param obj PCM info container + * \return available subdevices count of PCM + */ +unsigned int +snd_pcm_info_get_subdevices_avail (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_subdevices_avail()\n"); + + return 1; +} + +/** + * \brief get description of PCM sample format + * \param format PCM sample format + * \return ascii description of PCM sample format + */ +const char * +snd_pcm_format_description (snd_pcm_format_t format) +{ + if (format > SND_PCM_FORMAT_LAST) + return NULL; + return snd_pcm_format_descriptions[format]; +} + +/** + * \brief Get subdevices count from a PCM info container + * \param obj PCM info container + * \return subdevices total count of PCM + */ +unsigned int +snd_pcm_info_get_subdevices_count (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_subdevices_count()\n"); + + return 1; +} + +/** + * \brief Silence a PCM samples buffer + * \param format Sample format + * \param data Buffer + * \return samples Samples count + */ +int +snd_pcm_format_set_silence (snd_pcm_format_t format, void *data, + unsigned int samples) +{ + dbg_printf ("snd_pcm_format_set_silence()\n"); + + return 0; +} + + +/** + * \brief get identifier of PCM handle + * \param pcm PCM handle + * \return ascii identifier of PCM handle + * + * Returns the ASCII identifier of given PCM handle. It's the same + * identifier specified in snd_pcm_open(). + */ +const char * +snd_pcm_name (snd_pcm_t * pcm) +{ + return pcm->info.name; +} + +/** + * \brief get name of PCM state + * \param state PCM state + * \return ascii name of PCM state + */ +const char * +snd_pcm_state_name (snd_pcm_state_t state) +{ + if (state > SND_PCM_STATE_LAST) + return NULL; + return snd_pcm_state_names[state]; + +} + +/** + * \brief get name of PCM stream type + * \param stream PCM stream type + * \return ascii name of PCM stream type + */ +const char * +snd_pcm_stream_name (snd_pcm_stream_t stream) +{ + assert (stream <= SND_PCM_STREAM_LAST); + return snd_pcm_stream_names[stream]; +} + +/** + * \brief Extract maximum buffer time from a configuration space + * \param params Configuration space + * \param val approximate maximum buffer duration in us + * \param dir Sub unit direction + * \return 0 otherwise a negative error code + * + * Exact value is <,=,> the returned one following dir (-1,0,1) + */ +int INTERNAL (snd_pcm_hw_params_get_buffer_time_max) (const + snd_pcm_hw_params_t * + params, + unsigned int *val, + int *dir) +{ + dbg_printf ("snd_pcm_hw_params_get_buffer_time_max()\n"); + return 0; +} + +/** + * \brief Get subdevice name from a PCM info container + * \param obj PCM info container + * \return name of used PCM subdevice + */ +const char * +snd_pcm_info_get_subdevice_name (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_subdevice_name()\n"); + + return "OSS subname"; +} + +int +snd_device_name_hint (int card, const char * iface, void *** hints) +{ + dbg_printf ("snd_device_name_hint()\n"); + + return -1; +} + +int +snd_pcm_hw_params_is_monotonic (const snd_pcm_hw_params_t * params) +{ + return 0; +} + +/** + * \brief get PCM sample format from name + * \param name PCM sample format name (case insensitive) + * \return PCM sample format + */ +snd_pcm_format_t +snd_pcm_format_value (const char *name) +{ + snd_pcm_format_t format; + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) + { + if (snd_pcm_format_names[format] && + strcasecmp (name, snd_pcm_format_names[format]) == 0) + { + return format; + } + } + for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) + { + if (snd_pcm_format_descriptions[format] && + strcasecmp (name, snd_pcm_format_descriptions[format]) == 0) + { + return format; + } + } + return SND_PCM_FORMAT_UNKNOWN; +} + + +/** + * \brief Get id from a PCM info container + * \param obj PCM info container + * \return short id of PCM + */ +const char * +snd_pcm_info_get_id (const snd_pcm_info_t * obj) +{ + dbg_printf ("snd_pcm_info_get_id()\n"); + + return "OSS ID"; +} + +/** + * \brief Return nominal bits per a PCM sample + * \param format Sample format + * \return bits per sample, a negative error code if not applicable + */ +int +snd_pcm_format_width (snd_pcm_format_t format) +{ + switch (format) + { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: + return 18; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S20_3BE: + case SNDRV_PCM_FORMAT_U20_3LE: + case SNDRV_PCM_FORMAT_U20_3BE: + return 20; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_BE: + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_U24_BE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_U24_3BE: + return 24; + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: + return 64; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: + return 32; + case SNDRV_PCM_FORMAT_MU_LAW: + case SNDRV_PCM_FORMAT_A_LAW: + return 8; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + return 4; + default: + return -EINVAL; + } +} + + +/** + * \brief Add an async handler for a PCM + * \param handler Returned handler handle + * \param pcm PCM handle + * \param callback Callback function + * \param private_data Callback private data + * \return 0 otherwise a negative error code on failure + * + * The asynchronous callback is called when period boundary elapses. + */ +int +snd_async_add_pcm_handler (snd_async_handler_t ** handler, snd_pcm_t * pcm, + snd_async_callback_t callback, void *private_data) +{ + dbg_printf ("snd_async_add_pcm_handler()\n"); + + return -EINVAL; +} + +void * +snd_async_handler_get_callback_private (snd_async_handler_t * handler) +{ + // What's this? + dbg_printf ("snd_async_handler_get_callback_private()\n"); + return NULL; +} + +/* + * What's this? + */ +int +snd_pcm_format_linear (snd_pcm_format_t format) +{ + return 1; +} + +/* + * What's this? + */ +int +snd_pcm_format_float (snd_pcm_format_t format) +{ + return 0; +} + +/* + * What's this? + */ +int +snd_pcm_format_signed (snd_pcm_format_t format) +{ + return (format != SND_PCM_FORMAT_U8); +} + +/* + * What's this? + */ +snd_pcm_format_t +snd_pcm_build_linear_format (int width, int pwidth, int unsignd, + int big_endian) +{ + printf ("Invalid ALSA call snd_pcm_build_linear_format()\n"); + return 0; +} + +int +snd_pcm_format_cpu_endian (snd_pcm_format_t format) +{ + return 1; +} + +int +snd_pcm_format_little_endian (snd_pcm_format_t format) +{ + return 1; +} + +/** + * \brief get size of #snd_pcm_format_mask_t + * \return size in bytes + */ +size_t +snd_pcm_format_mask_sizeof () +{ + return sizeof (snd_pcm_format_mask_t); +} + +/** + * \brief test the presence of a format in a #snd_pcm_format_mask_t + * \param mask pointer to mask + * \param val format + */ +int +snd_pcm_format_mask_test (const snd_pcm_format_mask_t * mask, + snd_pcm_format_t val) +{ + printf ("snd_pcm_format_mask_test()\n"); + return 0; +} + +/** + * \brief Return PCM handle related to an async handler + * \param handler Async handler handle + * \return PCM handle + */ +snd_pcm_t * +snd_async_handler_get_pcm (snd_async_handler_t * handler) +{ + dbg_printf ("snd_async_handler_get_pcm()\n"); + return NULL; +} + +/** + * \brief Copy one or more areas + * \param dst_areas destination areas specification (one for each channel) + * \param dst_offset offset in frames inside destination area + * \param src_areas source areas specification (one for each channel) + * \param src_offset offset in frames inside source area + * \param channels channels count + * \param frames frames to copy + * \param format PCM sample format + * \return 0 on success otherwise a negative error code + */ +int +snd_pcm_areas_copy (const snd_pcm_channel_area_t * dst_areas, + snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t * src_areas, + snd_pcm_uframes_t src_offset, unsigned int channels, + snd_pcm_uframes_t frames, snd_pcm_format_t format) +{ + dbg_printf ("snd_pcm_areas_copy()\n"); + + return -EINVAL; +} + +/** + * \brief Get format mask from a configuration space + * \param params Configuration space + * \param mask Returned Format mask + */ +void +snd_pcm_hw_params_get_format_mask (snd_pcm_hw_params_t * params, + snd_pcm_format_mask_t * mask) +{ + printf ("snd_pcm_hw_params_get_format_mask()\n"); +} + +#if 1 + +#ifdef USE_VERSIONED_SYMBOLS + +#define OBSOLETE1(name, what, new) \ + symbol_version(__old_##name, name, what); \ + default_symbol_version(__##name, name, new); + +#else + +#define OBSOLETE1(name, what, new) \ + use_default_symbol_version(__##name, name, new); + +#endif /* USE_VERSIONED_SYMBOLS */ + +#define __P_OLD_GET(pfx, name, val_type, ret_type) \ +ret_type pfx##name(const snd_pcm_hw_params_t *params) \ +{ \ + val_type val; \ + if (INTERNAL(name)(params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_GET1(pfx, name, val_type, ret_type) \ +ret_type pfx##name(const snd_pcm_hw_params_t *params, int *dir) \ +{ \ + val_type val; \ + if (INTERNAL(name)(params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_GET(name, val_type, ret_type) __P_OLD_GET(__old_, name, val_type, ret_type) +#define __OLD_GET1(name, val_type, ret_type) __P_OLD_GET1(__old_, name, val_type, ret_type) + +#define __P_OLD_NEAR(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val) \ +{ \ + if (INTERNAL(name)(pcm, params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_NEAR1(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ret_type val, int *dir) \ +{ \ + if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_NEAR(name, ret_type) __P_OLD_NEAR(__old_, name, ret_type) +#define __OLD_NEAR1(name, ret_type) __P_OLD_NEAR1(__old_, name, ret_type) + +#define __P_OLD_SET_FL(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(pcm, params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __P_OLD_SET_FL1(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, int *dir) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(pcm, params, &val, dir) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_SET_FL(name, ret_type) __P_OLD_SET_FL(__old_, name, ret_type) +#define __OLD_SET_FL1(name, ret_type) __P_OLD_SET_FL1(__old_, name, ret_type) + +#define __P_OLD_GET_SW(pfx, name, ret_type) \ +ret_type pfx##name(snd_pcm_sw_params_t *params) \ +{ \ + ret_type val; \ + if (INTERNAL(name)(params, &val) < 0) \ + return 0; \ + return (ret_type)val; \ +} + +#define __OLD_GET_SW(name, ret_type) __P_OLD_GET_SW(__old_, name, ret_type) + +#endif /* DOC_HIDDEN */ + +__OLD_NEAR1 (snd_pcm_hw_params_set_rate_near, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_set_rate_near, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_NEAR (snd_pcm_hw_params_set_channels_near, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_set_channels_near, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_period_size, snd_pcm_uframes_t, + snd_pcm_sframes_t); +OBSOLETE1 (snd_pcm_hw_params_get_period_size, ALSA_0.9, ALSA_0.9.0rc4); + + +__OLD_NEAR1 (snd_pcm_hw_params_set_buffer_time_near, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_set_buffer_time_near, ALSA_0.9, + ALSA_0.9.0rc4) __OLD_GET (snd_pcm_hw_params_get_buffer_size, + snd_pcm_uframes_t, snd_pcm_sframes_t); +OBSOLETE1 (snd_pcm_hw_params_get_buffer_size, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_NEAR1 (snd_pcm_hw_params_set_period_time_near, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_set_period_time_near, ALSA_0.9, + ALSA_0.9.0rc4); + +__OLD_NEAR (snd_pcm_hw_params_set_buffer_size_near, snd_pcm_uframes_t); +OBSOLETE1 (snd_pcm_hw_params_set_buffer_size_near, ALSA_0.9, + ALSA_0.9.0rc4); + +__OLD_NEAR1 (snd_pcm_hw_params_set_period_size_near, snd_pcm_uframes_t); +OBSOLETE1 (snd_pcm_hw_params_set_period_size_near, ALSA_0.9, + ALSA_0.9.0rc4); + +__OLD_NEAR1 (snd_pcm_hw_params_set_periods_near, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_set_periods_near, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_period_time, unsigned int, int); +OBSOLETE1 (snd_pcm_hw_params_get_period_time, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_buffer_time, unsigned int, int); +OBSOLETE1 (snd_pcm_hw_params_get_buffer_time, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET_SW (snd_pcm_sw_params_get_xfer_align, snd_pcm_uframes_t); +OBSOLETE1 (snd_pcm_sw_params_get_xfer_align, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_periods, unsigned int, int); +OBSOLETE1 (snd_pcm_hw_params_get_periods, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET (snd_pcm_hw_params_get_access, snd_pcm_access_t, int); +OBSOLETE1 (snd_pcm_hw_params_get_access, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_buffer_time_max, unsigned int, + unsigned int); +OBSOLETE1 (snd_pcm_hw_params_get_buffer_time_max, ALSA_0.9, + ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_tick_time, unsigned int, int); +OBSOLETE1 (snd_pcm_hw_params_get_tick_time, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET (snd_pcm_hw_params_get_channels_max, unsigned int, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_get_channels_max, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET (snd_pcm_hw_params_get_channels_min, unsigned int, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_get_channels_min, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_rate_max, unsigned int, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_get_rate_max, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_rate_min, unsigned int, unsigned int); +OBSOLETE1 (snd_pcm_hw_params_get_rate_min, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET (snd_pcm_hw_params_get_format, snd_pcm_format_t, int); +OBSOLETE1 (snd_pcm_hw_params_get_format, ALSA_0.9, ALSA_0.9.0rc4); + +__OLD_GET1 (snd_pcm_hw_params_get_rate, unsigned int, int); +OBSOLETE1 (snd_pcm_hw_params_get_rate, ALSA_0.9, ALSA_0.9.0rc4); diff --git a/lib/libsalsa/rawmidi.c b/lib/libsalsa/rawmidi.c new file mode 100644 index 0000000..4246357 --- /dev/null +++ b/lib/libsalsa/rawmidi.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +/** + * \brief Opens a new connection to the RawMidi interface. + * \param inputp Returned input handle (NULL if not wanted) + * \param outputp Returned output handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int +snd_rawmidi_open (snd_rawmidi_t ** inputp, snd_rawmidi_t ** outputp, + const char *name, int mode) +{ + dbg_printf ("snd_rawmidi_open(%s)\n", name); + + ALIB_INIT (); + + if (!alib_appcheck ()) + return -ENODEV; + + return 0; +} + +/** + * \brief close RawMidi handle + * \param rawmidi RawMidi handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified RawMidi handle and frees all associated + * resources. + */ +int +snd_rawmidi_close (snd_rawmidi_t * rawmidi) +{ + dbg_printf ("snd_rawmidi_close()\n"); + + return 0; +} + +/** + * \brief read MIDI bytes from MIDI stream + * \param rawmidi RawMidi handle + * \param buffer buffer to store the input MIDI bytes + * \param size input buffer size in bytes + */ +ssize_t +snd_rawmidi_read (snd_rawmidi_t * rawmidi, void *buffer, size_t size) +{ + dbg_printf ("snd_rawmidi_read(%d)\n", size); +} + +/** + * \brief write MIDI bytes to MIDI stream + * \param rawmidi RawMidi handle + * \param buffer buffer containing MIDI bytes + * \param size output buffer size in bytes + */ +ssize_t +snd_rawmidi_write (snd_rawmidi_t * rawmidi, const void *buffer, size_t size) +{ + dbg_printf ("snd_rawmidi_write(%d)\n", size); + + return size; +} + + +/** + * \brief set nonblock mode + * \param rawmidi RawMidi handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + * + * The nonblock mode cannot be used when the stream is in + * #SND_RAWMIDI_APPEND state. + */ +int +snd_rawmidi_nonblock (snd_rawmidi_t * rawmidi, int nonblock) +{ + dbg_printf ("snd_rawmidi_nonblock(%d)\n", nonblock); + + return 0; +} + +/** + * \brief get count of poll descriptors for RawMidi handle + * \param rawmidi RawMidi handle + * \return count of poll descriptors + */ +int +snd_rawmidi_poll_descriptors_count (snd_rawmidi_t * rawmidi) +{ + dbg_printf ("snd_rawmidi_poll_descriptors_count()\n"); + + return 0; +} + +/** + * \brief get poll descriptors + * \param rawmidi RawMidi handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \return count of filled descriptors + */ +int +snd_rawmidi_poll_descriptors (snd_rawmidi_t * rawmidi, struct pollfd *pfds, + unsigned int space) +{ + dbg_printf ("snd_rawmidi_poll_descriptors()\n"); + + return 0; +} + +/** + * \brief get returned events from poll descriptors + * \param pcm rawmidi RawMidi handle + * \param pfds array of poll descriptors + * \param nfds count of poll descriptors + * \param revents returned events + * \return zero if success, otherwise a negative error code + */ +int +snd_rawmidi_poll_descriptors_revents (snd_rawmidi_t * rawmidi, struct pollfd + *pfds, unsigned int nfds, + unsigned short *revents) +{ + dbg_printf ("snd_rawmidi_poll_descriptors_revents()\n"); + + return 0; +} + +/** + * \brief get size of the snd_rawmidi_info_t structure in bytes + * \return size of the snd_rawmidi_info_t structure in bytes + */ +size_t +snd_rawmidi_info_sizeof () +{ + return sizeof (snd_rawmidi_info_t); +} + +/** + * \brief get rawmidi hardware driver name + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi hardware driver name + */ +const char * +snd_rawmidi_info_get_name (const snd_rawmidi_info_t * info) +{ + dbg_printf ("snd_rawmidi_info_get_name()\n"); + + return "OSS rawmidi"; +} + +/** + * \brief get rawmidi count of subdevices + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi count of subdevices + */ +unsigned int +snd_rawmidi_info_get_subdevices_count (const snd_rawmidi_info_t * info) +{ + dbg_printf ("snd_rawmidi_info_get_subdevices_count()\n"); + + return 1; +} + +/** + * \brief set rawmidi device number + * \param info pointer to a snd_rawmidi_info_t structure + * \param val device number + */ +void +snd_rawmidi_info_set_device (snd_rawmidi_info_t * info, unsigned int val) +{ + dbg_printf ("snd_rawmidi_info_set_device(%d)\n", val); + +} + + +/** + * \brief set rawmidi subdevice number + * \param info pointer to a snd_rawmidi_info_t structure + * \param val subdevice number + */ +void +snd_rawmidi_info_set_subdevice (snd_rawmidi_info_t * info, unsigned int val) +{ + dbg_printf ("snd_rawmidi_info_set_subdevice(%d)\n", val); +} + +/** + * \brief set rawmidi stream identifier + * \param info pointer to a snd_rawmidi_info_t structure + * \param val rawmidi stream identifier + */ +void +snd_rawmidi_info_set_stream (snd_rawmidi_info_t * info, + snd_rawmidi_stream_t val) +{ + dbg_printf ("snd_rawmidi_info_set_stream(%d)\n", val); +} + +/** + * \brief get rawmidi subdevice name + * \param info pointer to a snd_rawmidi_info_t structure + * \return rawmidi subdevice name + */ +const char * +snd_rawmidi_info_get_subdevice_name (const snd_rawmidi_info_t * info) +{ + dbg_printf ("snd_rawmidi_info_get_subdevice_name()\n"); + + return "OSS rawmidi subdevice"; +} diff --git a/lib/libsalsa/seq.c b/lib/libsalsa/seq.c new file mode 100644 index 0000000..67f134b --- /dev/null +++ b/lib/libsalsa/seq.c @@ -0,0 +1,2230 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +static int nports = 0; + +typedef struct _snd_seq_port_subscribe +{ + int dummy; +} snd_seq_port_subscribe_t; + +typedef struct _snd_seq_queue_tempo +{ + int dummy; +} snd_seq_queue_tempo_t; + +typedef struct _snd_seq_system_info +{ + int dummy; +} snd_seq_system_info_t; + +struct _snd_seq_remove_events +{ + int dummy; +}; + +struct _snd_seq_query_subscribe +{ + int dummy; +}; + +/** + * \brief Open the ALSA sequencer + * + * \param seqp Pointer to a snd_seq_t pointer. This pointer must be + * kept and passed to most of the other sequencer functions. + * \param name The sequencer's "name". This is \em not a name you make + * up for your own purposes; it has special significance to the ALSA + * library. Usually you need to pass \c "default" here. + * \param streams The read/write mode of the sequencer. Can be one of + * three values: + * - #SND_SEQ_OPEN_OUTPUT - open the sequencer for output only + * - #SND_SEQ_OPEN_INPUT - open the sequencer for input only + * - #SND_SEQ_OPEN_DUPLEX - open the sequencer for output and input + * \note Internally, these are translated to \c O_WRONLY, \c O_RDONLY and + * \c O_RDWR respectively and used as the second argument to the C library + * open() call. + * \param mode Optional modifier. Can be either 0, or + * #SND_SEQ_NONBLOCK, which will make read/write operations + * non-blocking. This can also be set later using #snd_seq_nonblock(). + * \return 0 on success otherwise a negative error code + * +* Creates a new handle and opens a connection to the kernel + * sequencer interface. + * After a client is created successfully, an event + * with #SND_SEQ_EVENT_CLIENT_START is broadcast to announce port. + * + * \sa snd_seq_open_lconf(), snd_seq_close(), snd_seq_type(), snd_seq_name(), + * snd_seq_nonblock(), snd_seq_client_id() + */ +int +snd_seq_open (snd_seq_t ** seqp, const char *name, int streams, int mode) +{ + snd_seq_t *seq; + int err, oss_mode; + static int instance = 0; + + char *fname = "/dev/midi", *envname = NULL, tmp[128]; + + ALIB_INIT (); + + dbg_printf ("snd_seq_open(name='%s', streams=%d, mode=%x)\n", name, streams, + mode); + + if (!alib_appcheck ()) + return -ENODEV; + + instance++; + + sprintf (tmp, "%s_mididev%d", alib_appname, instance); + + if ((envname = getenv (tmp)) != NULL) + { + fname = envname; + } +#if 0 + if (streams != 1) + { + fprintf (stderr, "salsa: snd_seq_open doesn't support streams=%d\n", + streams); + return -EIO; + } +#endif + + if ((seq = malloc (sizeof (*seq))) == NULL) + return -ENOMEM; + + dbg_printf ("Created sequencer seq=%x\n", seq); + + memset (seq, 0, sizeof (*seq)); + + switch (streams) + { + case SND_SEQ_OPEN_INPUT: + oss_mode = O_RDONLY; + dbg_printf ("Open SND_SEQ_OPEN_INPUT\n"); + break; + case SND_SEQ_OPEN_OUTPUT: + oss_mode = O_WRONLY; + dbg_printf ("Open SND_SEQ_OPEN_OUTPUT\n"); + break; + case SND_SEQ_OPEN_DUPLEX: + dbg_printf ("SND_SEQ_OPEN_DUPLEX\n"); + oss_mode = O_RDWR; + break; + + default: + fprintf (stderr, "snd_seq_open: Unknown stream %x\n", streams); + return -ENODEV; + } + + if ((seq->fd = open (fname, oss_mode, 0)) == -1) + { + err = errno; + perror (fname); + + if (envname == NULL) + { + fprintf (stderr, + "You can select another filename using environment variable %s_mididev%d\n", + alib_appname, instance); + } + return -err; + } + + seq->streams = streams; + seq->oss_mode = oss_mode; + + if (streams == SND_SEQ_OPEN_INPUT || streams == SND_SEQ_OPEN_DUPLEX) + { + seq->parser = midiparser_create (midiparser_callback, seq); + if (seq->parser == NULL) + { + fprintf (stderr, "libsalsa: Can't create MIDI parser\n"); + return -ENODEV; + } + } + + *seqp = seq; + return 0; +} + +/** + * \brief Close the sequencer + * \param handle Handle returned from #snd_seq_open() + * \return 0 on success otherwise a negative error code + * + * Closes the sequencer client and releases its resources. + * After a client is closed, an event with + * #SND_SEQ_EVENT_CLIENT_EXIT is broadcast to announce port. + * The connection between other clients are disconnected. + * Call this just before exiting your program. + * + * \sa snd_seq_close() + */ +int +snd_seq_close (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_close(seq=%x)\n", seq); + + close (seq->fd); + free (seq); +} + +/** + * \brief Set nonblock mode + * \param seq sequencer handle + * \param nonblock 0 = block, 1 = nonblock mode + * \return 0 on success otherwise a negative error code + * + * Change the blocking mode of the given client. + * In block mode, the client falls into sleep when it fills the + * output memory pool with full events. The client will be woken up + * after a certain amount of free space becomes available. + * + * \sa snd_seq_open() + */ +int +snd_seq_nonblock (snd_seq_t * seq, int nonblock) +{ + dbg_printf ("snd_seq_nonblock(seq=%x, nonblock=%d)\n", seq, nonblock); + + seq->nonblock = nonblock; + return 0; +} + +/** + * \brief create a sequencer port on the current client + * \param seq sequencer handle + * \param port port information for the new port + * \return 0 on success otherwise a negative error code + * + * Creates a sequencer port on the current client. + * The attributes of created port is specified in \a info argument. + * + * The client field in \a info argument is overwritten with the current client id. + * The port id to be created can be specified via #snd_seq_port_info_set_port_specified. + * You can get the created port id by reading the port pointer via #snd_seq_port_info_get_port. + * + * Each port has the capability bit-masks to specify the access capability + * of the port from other clients. + * The capability bit flags are defined as follows: + * - #SND_SEQ_PORT_CAP_READ Readable from this port + * - #SND_SEQ_PORT_CAP_WRITE Writable to this port. + * - #SND_SEQ_PORT_CAP_SYNC_READ For synchronization (not implemented) + * - #SND_SEQ_PORT_CAP_SYNC_WRITE For synchronization (not implemented) + * - #SND_SEQ_PORT_CAP_DUPLEX Read/write duplex access is supported + * - #SND_SEQ_PORT_CAP_SUBS_READ Read subscription is allowed + * - #SND_SEQ_PORT_CAP_SUBS_WRITE Write subscription is allowed + * - #SND_SEQ_PORT_CAP_SUBS_NO_EXPORT Subscription management from 3rd client is disallowed + * + * Each port has also the type bitmasks defined as follows: + * - #SND_SEQ_PORT_TYPE_SPECIFIC Hardware specific port + * - #SND_SEQ_PORT_TYPE_MIDI_GENERIC Generic MIDI device + * - #SND_SEQ_PORT_TYPE_MIDI_GM General MIDI compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_GS GS compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_XG XG compatible device + * - #SND_SEQ_PORT_TYPE_MIDI_MT32 MT-32 compatible device + * - #SND_SEQ_PORT_TYPE_SYNTH Synth device + * - #SND_SEQ_PORT_TYPE_DIRECT_SAMPLE Sampling device (supporting download) + * - #SND_SEQ_PORT_TYPE_SAMPLE Sampling device (sample can be downloaded at any time) + * - #SND_SEQ_PORT_TYPE_APPLICATION Application (sequencer/editor) + * + * A port may contain specific midi channels, midi voices and synth voices. + * These values could be zero as default. + * + * \sa snd_seq_delete_port(), snd_seq_get_port_info(), + * snd_seq_create_simple_port() + */ +int +snd_seq_create_port (snd_seq_t * seq, snd_seq_port_info_t * port) +{ + dbg_printf ("snd_seq_create_port(seq=%x, port=%x)\n", seq, port); + + port->port = nports++; + return 0; +} + +/** + * \brief Get the client id + * \param seq sequencer handle + * \return the client id + * + * Returns the id of the specified client. + * If an error occurs, function returns the negative error code. + * A client id is necessary to inquiry or to set the client information. + * A user client is assigned from 128 to 191. + * + * \sa snd_seq_open() + */ +int +snd_seq_client_id (snd_seq_t * seq) +{ + static int client_id = 128; + + dbg_printf ("snd_seq_client_id(seq=%x)=%d\n", seq, client_id); + + return client_id++; +} + +/** + * \brief Get client id of a client_info container + * \param info client_info container + * \return client id + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_client(), snd_seq_client_id() + */ +int +snd_seq_client_info_get_client (const snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_client_info_get_client()\n"); + + return 0; +} + +/** + * \brief Get client type of a client_info container + * \param info client_info container + * \return client type + * + * The client type is either #SEQ_CLIENT_TYPE_KERNEL or #SEQ_CLIENT_TYPE_USER + * for kernel or user client respectively. + * + * \sa snd_seq_get_client_info() + */ +snd_seq_client_type_t +snd_seq_client_info_get_type (const snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_client_info_get_type(infp=%x)\n", info); + + return SND_SEQ_KERNEL_CLIENT; // TODO +} + +/** + * \brief Set the client id of a client_info container + * \param info client_info container + * \param client client id + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_client() + */ +void +snd_seq_client_info_set_client (snd_seq_client_info_t * info, int client) +{ + dbg_printf ("snd_seq_client_info_set_client(%x, %d)\n", info, client); + + info->client = client; +} + +/** + * \brief get size of #snd_seq_client_info_t + * \return size in bytes + */ +size_t +snd_seq_client_info_sizeof () +{ + dbg_printf ("snd_seq_client_info_sizeof()\n"); + + return sizeof (snd_seq_client_info_t); +} + +/** + * \brief retrieve an event from sequencer + * \param seq sequencer handle + * \param ev event pointer to be stored + * \return + * + * Obtains an input event from sequencer. + * The event is created via snd_seq_create_event(), and its pointer is stored on * ev argument. + * + * This function firstly receives the event byte-stream data from sequencer + * as much as possible at once. Then it retrieves the first event record + * and store the pointer on ev. + * By calling this function sequentially, events are extracted from the input buffer. + * + * If there is no input from sequencer, function falls into sleep + * in blocking mode until an event is received, + * or returns \c -EAGAIN error in non-blocking mode. + * Occasionally, this function may return \c -ENOSPC error. + * This means that the input FIFO of sequencer overran, and some events are + * lost. + * Once this error is returned, the input FIFO is cleared automatically. + * + * Function returns the byte size of remaining events on the input buffer + * if an event is successfully received. + * Application can determine from the returned value whether to call + * input once more or not. + * + * \sa snd_seq_event_input_pending(), snd_seq_drop_input() + */ +int +snd_seq_event_input (snd_seq_t * seq, snd_seq_event_t ** evp) +{ + static snd_seq_event_t *ev; + unsigned char buf[256]; + int i, l; + + dbg_printf2 ("snd_seq_event_input(seq=%x)\n", seq); + + while (1) + { + + if (seq->nextevent < seq->nevents) + { + *evp = &seq->events[seq->nextevent++]; + + return (seq->nevents - seq->nextevent) * sizeof (snd_seq_event_t); + } + + seq->nextevent = seq->nevents = 0; + memset (seq->events, 0, sizeof (seq->events)); + + // TODO Handling of nonblocking mode + if ((l = read (seq->fd, buf, sizeof (buf))) == -1) + return -errno; + + midiparser_input_buf (seq->parser, buf, l); + + } + +} + +/** + * \brief output an event directly to the sequencer NOT through output buffer + * \param seq sequencer handle + * \param ev event to be output + * \return the byte size sent to sequencer or a negative error code + * + * This function sends an event to the sequencer directly not through the + * output buffer. When the event is a variable length event, a temporary + * buffer is allocated inside alsa-lib and the data is copied there before + * actually sent. + * + * \sa snd_seq_event_output() + */ +int +snd_seq_event_output_direct (snd_seq_t * seq, snd_seq_event_t * ev) +{ + int err; + + dbg_printf3 ("snd_seq_event_output_direct()\n"); + + if ((err = convert_event (seq, ev)) < 0) + return err; + if ((err = snd_seq_drain_output (seq)) < 0) + return err; + + return 0; +} + +/** + * \brief (DEPRECATED) free an event + * + * In the former version, this function was used to + * release the event pointer which was allocated by snd_seq_event_input(). + * In the current version, the event record is not allocated, so + * you don't have to call this function any more. + */ +int +snd_seq_free_event (snd_seq_event_t * ev) +{ + return 0; +} + +/** + * \brief obtain the current client information + * \param seq sequencer handle + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the current client stored on info. + * client and type fields are ignored. + * + * \sa snd_seq_get_any_client_info(), snd_seq_set_client_info(), + * snd_seq_query_next_client() + */ +int +snd_seq_get_client_info (snd_seq_t * seq, snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_get_client_info(seq=%x, info=%x)\n", seq, info); + + return 0; +} + +/** + * \brief query the next matching port + * \param seq sequencer handle + * \param info query pattern and result + + * Queries the next matching port on the client specified in + * \a info argument. + * The search begins at the next port specified in + * port field of \a info argument. + * For finding the first port at a certain client, give -1. + * + * If a matching port is found, its attributes are stored on + * \a info and function returns zero. + * Otherwise, a negative error code is returned. + * + * \sa snd_seq_get_port_info() + */ +int +snd_seq_query_next_port (snd_seq_t * seq, snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_query_next_port()\n"); + + return -EINVAL; +} + +/** + * \brief Set the name of a client_info container + * \param info client_info container + * \param name name string + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_get_name(), + * snd_seq_set_client_name() + */ +void +snd_seq_client_info_set_name (snd_seq_client_info_t * info, const char *name) +{ + dbg_printf ("snd_seq_client_info_set_name(%s)\n", name); + + strncpy (info->name, name, sizeof (info->name) - 1); + info->name[sizeof (info->name) - 1] = 0; +} + +/** + * \brief subscribe a port connection + * \param seq sequencer handle + * \param sub subscription information + * \return 0 on success otherwise a negative error code + * + * Subscribes a connection between two ports. + * The subscription information is stored in sub argument. + * + * \sa snd_seq_get_port_subscription(), snd_seq_unsubscribe_port(), + * snd_seq_connect_from(), snd_seq_connect_to() + */ +int +snd_seq_subscribe_port (snd_seq_t * seq, snd_seq_port_subscribe_t * sub) +{ + dbg_printf ("snd_seq_subscribe_port()\n"); + + return -EINVAL; +} + +/** + * \brief get size of #snd_seq_port_subscribe_t + * \return size in bytes + */ +size_t +snd_seq_port_subscribe_sizeof () +{ + return sizeof (snd_seq_port_subscribe_t); +} + +/** + * \brief Set sender address of a port_subscribe container + * \param info port_subscribe container + * \param addr sender address + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_sender() + */ +void +snd_seq_port_subscribe_set_sender (snd_seq_port_subscribe_t * info, + const snd_seq_addr_t * addr) +{ + dbg_printf ("snd_seq_port_subscribe_set_sender()\n"); +} + +/** + * \brief Set destination address of a port_subscribe container + * \param info port_subscribe container + * \param addr destination address + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_dest() + */ +void +snd_seq_port_subscribe_set_dest (snd_seq_port_subscribe_t * info, + const snd_seq_addr_t * addr) +{ + dbg_printf ("snd_seq_port_subscribe_set_dest()\n"); +} + +/** + * \brief Set the queue id of a port_subscribe container + * \param info port_subscribe container + * \param q queue id + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_queue() + */ +void +snd_seq_port_subscribe_set_queue (snd_seq_port_subscribe_t * info, int q) +{ + dbg_printf ("snd_seq_port_subscribe_set_queue()\n"); +} + +/** + * \brief Set the real-time mode of a port_subscribe container + * \param info port_subscribe container + * \param val non-zero to enable + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_real() + */ +void +snd_seq_port_subscribe_set_time_real (snd_seq_port_subscribe_t * info, + int val) +{ + dbg_printf ("snd_seq_port_subscribe_set_time_real()\n"); +} + +/** + * \brief Set the time-update mode of a port_subscribe container + * \param info port_subscribe container + * \param val non-zero to enable + * + * \sa snd_seq_subscribe_port(), snd_seq_port_subscribe_get_time_update() + */ +void +snd_seq_port_subscribe_set_time_update (snd_seq_port_subscribe_t * info, int + val) +{ + dbg_printf ("snd_seq_port_subscribe_set_time_update()\n"); +} + +/* + * Port + */ + +/** + * \brief get size of #snd_seq_port_info_t + * \return size in bytes + */ +size_t +snd_seq_port_info_sizeof () +{ + return sizeof (snd_seq_port_info_t); +} + +/** + * \brief Get the capability bits of a port_info container + * \param info port_info container + * \return capability bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_capability() + */ +unsigned int +snd_seq_port_info_get_capability (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_capability()\n"); + + return info->capability; +} + +/** + * \brief Get client/port address of a port_info container + * \param info port_info container + * \return client/port address pointer + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_addr() + */ +const snd_seq_addr_t * +snd_seq_port_info_get_addr (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_addr(info=%x)\n", info); + + return NULL; // TODO +} + +/** + * \brief set the capability bits of a port_info container + * \param info port_info container + * \param capability capability bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_capability() + */ +void +snd_seq_port_info_set_capability (snd_seq_port_info_t * info, + unsigned int capability) +{ + dbg_printf ("snd_seq_port_info_set_capability()\n"); +} + +/** + * \brief Set the port-specified mode of a port_info container + * \param info port_info container + * \param val non-zero if specifying the port id at creation + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port_specified() + */ +void +snd_seq_port_info_set_port_specified (snd_seq_port_info_t * info, int val) +{ + dbg_printf ("snd_seq_port_info_set_port_specified()\n"); +} + +/** + * \brief Get the midi channels of a port_info container + * \param info port_info container + * \return number of midi channels (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_midi_channels() + */ +int +snd_seq_port_info_get_midi_channels (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_midi_channels(info=%x)=%d\n", + info, info->midi_channels); + + return info->midi_channels; +} + +/** + * \brief set the midi channels of a port_info container + * \param info port_info container + * \param channels midi channels (default 0) + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_midi_channels() + */ +void +snd_seq_port_info_set_midi_channels (snd_seq_port_info_t * info, int channels) +{ + dbg_printf ("snd_seq_port_info_set_midi_channels(info=%x, channels=%d)\n", + info, channels); + info->midi_channels = channels; +} + +/** + * \brief Get the queue id to update timestamps + * \param info port_info container + * \return the queue id to get the timestamps + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_queue() + */ +int +snd_seq_port_info_get_timestamp_queue (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_timestamp_queue(info=%x)\n", info); + + return 0; // TODO +} + +/** + * \brief Set the queue id for timestamping + * \param info port_info container + * \param queue the queue id to get timestamps + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_queue() + */ +void +snd_seq_port_info_set_timestamp_queue (snd_seq_port_info_t * info, int queue) +{ + dbg_printf ("snd_seq_port_info_set_timestamp_queue(info=%x, queue=%d)\n", + info, queue); + + // TODO +} + +/** + * \brief Get whether the time-stamping of the given port is real-time mode + * \param info port_info container + * \return 1 if the time-stamping is in the real-time mode + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamp_real() + */ +int +snd_seq_port_info_get_timestamp_real (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_timestamp_real(info=%x)\n", info); + + return 0; // TODO +} + +/** + * \brief Set whether the timestime is updated in the real-time mode + * \param info port_info container + * \param enable non-zero if updating the timestamps in real-time mode + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamp_real() + */ +void +snd_seq_port_info_set_timestamp_real (snd_seq_port_info_t * info, int enable) +{ + dbg_printf ("snd_seq_port_info_set_timestamp_real(infp=%x, enable=%d)\n", + info, enable); +} + +/** + * \brief Get the time-stamping mode of the given port in a port_info container * \param info port_info container + * \return 1 if the port updates timestamps of incoming events + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_timestamping() + */ +int +snd_seq_port_info_get_timestamping (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_timestamping(info=%x)\n", info); + + return 0; // TODO +} + +/** + * \brief Set the time-stamping mode of the given port + * \param info port_info container + * \param enable non-zero if updating the timestamps of incoming events + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_timestamping() + */ +void +snd_seq_port_info_set_timestamping (snd_seq_port_info_t * info, int enable) +{ + dbg_printf ("snd_seq_port_info_set_timestamping(info=%x, enable=%d)\n", + info, enable); + + // TODO +} + +/** + * \brief Set the name of a port_info container + * \param info port_info container + * \param name name string + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_name() + */ +void +snd_seq_port_info_set_name (snd_seq_port_info_t * info, const char *name) +{ + dbg_printf ("snd_seq_port_info_set_name()\n"); + + strncpy (info->name, name, sizeof (info->name)); +} + +/** + * \brief Get the name of a port_info container + * \param info port_info container + * \return name string + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_name() + */ +const char * +snd_seq_port_info_get_name (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_name()\n"); + + return "Port Name"; +} + +/** + * \brief Get port id of a port_info container + * \param info port_info container + * \return port id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port() + */ +int +snd_seq_port_info_get_port (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_port()\n"); + + return -EIO; +} + +/** + * \brief Get the type bits of a port_info container + * \param info port_info container + * \return port type bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_type() + */ +unsigned int +snd_seq_port_info_get_type (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_type()\n"); + + return info->type; +} + +/** + * \brief Set the client id of a port_info container + * \param info port_info container + * \param client client id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_client() + */ +void +snd_seq_port_info_set_client (snd_seq_port_info_t * info, int client) +{ + dbg_printf ("snd_seq_port_info_set_client()\n"); +} + +/** + * \brief Set the port id of a port_info container + * \param info port_info container + * \param port port id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_port() + */ +void +snd_seq_port_info_set_port (snd_seq_port_info_t * info, int port) +{ + dbg_printf ("snd_seq_port_info_set_port()\n"); +} + +/** + * \brief query the next matching client + * \param seq sequencer handle + * \param info query pattern and result + * + * Queries the next matching client with the given condition in + * info argument. + * The search begins at the client with an id one greater than + * client field in info. + * If name field in info is not empty, the client name is compared. + * If a matching client is found, its attributes are stored o + * info and returns zero. + * Otherwise returns a negative error code. + * + * \sa snd_seq_get_any_client_info() + */ +int +snd_seq_query_next_client (snd_seq_t * seq, snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_query_next_client()\n"); + + return -EIO; +} + +/** + * \brief set the current client information + * \param seq sequencer handle + * \param info the client info data to set + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the current client stored on info. + * client and type fields are ignored. + * + * \sa snd_seq_get_client_info() + */ +int +snd_seq_set_client_info (snd_seq_t * seq, snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_set_client_info(seq=%x, info=%x)\n", seq, info); + + if (*info->name) + { + strcpy (seq->name, info->name); + ioctl (seq->fd, SNDCTL_SETNAME, seq->name); + ioctl (seq->fd, SNDCTL_SETSONG, seq->name); + } + + return 0; +} + +/** + * \brief check events in input buffer + * \return the byte size of remaining input events on input buffer. + * + * If events remain on the input buffer of user-space, function returns + * the total byte size of events on it. + * If fetch_sequencer argument is non-zero, + * this function checks the presence of events on sequencer FIFO + * When events exist, they are transferred to the input buffer, + * and the number of received events are returned. + * If fetch_sequencer argument is zero and + * no events remain on the input buffer, function simply returns zero. + * + * \sa snd_seq_event_input() + */ +int +snd_seq_event_input_pending (snd_seq_t * seq, int fetch_sequencer) +{ + dbg_printf ("snd_seq_event_input_pending()\n"); + + return 0; +} + +/** + * \brief Get poll descriptors + * \param seq sequencer handle + * \param pfds array of poll descriptors + * \param space space in the poll descriptor array + * \param events polling events to be checked (\c POLLIN and \c POLLOUT) + * \return count of filled descriptors + * + * Get poll descriptors assigned to the sequencer handle. + * Since a sequencer handle can duplex streams, you need to set which direction(s) + * is/are polled in \a events argument. When \c POLLIN bit is specified, + * the incoming events to the ports are checked. + * + * To check the returned poll-events, call #snd_seq_poll_descriptors_revents() + * instead of reading the pollfd structs directly. + * + * \sa snd_seq_poll_descriptors_count(), snd_seq_poll_descriptors_revents() + */ +int +snd_seq_poll_descriptors (snd_seq_t * seq, struct pollfd *pfds, + unsigned int space, short events) +{ + dbg_printf ("snd_seq_poll_descriptors(seq=%x)\n", seq); + + pfds->fd = seq->fd; + pfds->events = 0; + pfds->revents = 0; + + if (seq->oss_mode == O_WRONLY || seq->oss_mode == O_RDWR) + pfds->events = POLLOUT; + if (seq->oss_mode == O_RDONLY || seq->oss_mode == O_RDWR) + pfds->events = POLLIN; + + return 1; +} + + +/** + * \brief Returns the number of poll descriptors + * \param seq sequencer handle + * \param events the poll events to be checked (\c POLLIN and \c POLLOUT) + * \return the number of poll descriptors. + * + * Get the number of poll descriptors. The polling events to be checked + * can be specified by the second argument. When both input and output + * are checked, pass \c POLLIN|POLLOUT + * + * \sa snd_seq_poll_descriptors() + */ +int +snd_seq_poll_descriptors_count (snd_seq_t * seq, short events) +{ + dbg_printf ("snd_seq_poll_descriptors_count(seq=%x, events=%x)\n", + seq, events); + return 1; +} + +/** + * \brief create a queue + * \param seq sequencer handle + * \param info queue information to initialize + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int +snd_seq_create_queue (snd_seq_t * seq, snd_seq_queue_info_t * info) +{ + dbg_printf ("snd_seq_create_queue()\n"); + + return 0; +} + +/** + * \brief simple subscription (w/o exclusive & time conversion) + * \param myport the port id as sender + * \param dest_client destination client id + * \param dest_port destination port id + * \return 0 on success or negative error code + * + * Connect from the given receiver port in the current client + * to the given destination client:port. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_to() + */ +int +snd_seq_connect_to (snd_seq_t * seq, int myport, int dest_client, + int dest_port) +{ + dbg_printf ("snd_seq_connect_to(%d->%d/%d)\n", myport, dest_client, + dest_port); + + return 0; +} + +/** + * \brief simple subscription (w/o exclusive & time conversion) + * \param myport the port id as receiver + * \param src_client sender client id + * \param src_port sender port id + * \return 0 on success or negative error code + * + * Connect from the given sender client:port to the given destination port in the + * current client. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from() + */ +int +snd_seq_connect_from (snd_seq_t * seq, int myport, int src_client, + int src_port) +{ + dbg_printf + ("snd_seq_connect_from(seq=%x, myport=%d, src_client=%d, src_port=%d)\n", + seq, myport, src_client, src_port); + + return 0; +} + +/** + * \brief queue controls - start/stop/continue + * \param seq sequencer handle + * \param q queue id to control + * \param type event type + * \param value event value + * \param ev event instance + * + * This function sets up general queue control event and sends it. + * To send at scheduled time, set the schedule in \a ev. + * If \a ev is NULL, the event is composed locally and sent immediately + * to the specified queue. In any cases, you need to call #snd_seq_drain_output() + * appropriately to feed the event. + * + * \sa snd_seq_alloc_queue() + */ +int +snd_seq_control_queue (snd_seq_t * seq, int q, int type, int value, + snd_seq_event_t * ev) +{ + dbg_printf ("snd_seq_control_queue()\n"); + + return 0; +} + +/** + * \brief drain output buffer to sequencer + * \param seq sequencer handle + * \return 0 when all events are drained and sent to sequencer. + * When events still remain on the buffer, the byte size of remaining + * events are returned. On error a negative error code is returned. + * + * This function drains all pending events on the output buffer. + * The function returns immediately after the events are sent to the queues + * regardless whether the events are processed or not. + * To get synchronization with the all event processes, use + * #snd_seq_sync_output_queue() after calling this function. + * + * \sa snd_seq_event_output(), snd_seq_sync_output_queue() + */ +int +snd_seq_drain_output (snd_seq_t * seq) +{ + dbg_printf3 ("snd_seq_drain_output(seq=%x)\n", seq); + + return 0; +} + + +/** + * \brief remove all events on output buffer + * \param seq sequencer handle + * + * Removes all events on both user-space output buffer and + * output memory pool on kernel. + * + * \sa snd_seq_drain_output(), snd_seq_drop_output_buffer(), snd_seq_remove_events() + */ +int +snd_seq_drop_output (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_drop_output()\n"); + + return 0; +} + +/** + * \brief output an event + * \param seq sequencer handle + * \param ev event to be output + * \return the number of remaining events or a negative error code + * + * An event is once expanded on the output buffer. + * The output buffer will be drained automatically if it becomes full. + * + * If events remain unprocessed on output buffer before drained, + * the size of total byte data on output buffer is returned. + * If the output buffer is empty, this returns zero. + * + * \sa snd_seq_event_output_direct(), snd_seq_event_output_buffer(), + * snd_seq_event_output_pending(), snd_seq_drain_output(), + * snd_seq_drop_output(), snd_seq_extract_output(), + * snd_seq_remove_events() + */ +int +snd_seq_event_output (snd_seq_t * seq, snd_seq_event_t * ev) +{ + dbg_printf3 ("snd_seq_event_output(seq=%x, ev=%x)\n", seq, ev); + + return convert_event (seq, ev); +} + +/** + * \brief delete the specified queue + * \param seq sequencer handle + * \param q queue id to delete + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int +snd_seq_free_queue (snd_seq_t * seq, int q) +{ + dbg_printf ("snd_seq_free_queue()\n"); + + return 0; +} + +/** + * \brief obtain the information of the given client + * \param seq sequencer handle + * \param client client id + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Obtains the information of the client with a client id specified by + * info argument. + * The obtained information is written on info parameter. + * + * \sa snd_seq_get_client_info() + */ +int +snd_seq_get_any_client_info (snd_seq_t * seq, int client, + snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_get_any_client_info()\n"); + + strcpy (info->name, seq->name); + + return 0; +} + +/** + * \brief obtain the information of a port on an arbitrary client + * \param seq sequencer handle + * \param client client id to get + * \param port port id to get + * \param info pointer information returns + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_port_info() + */ +int +snd_seq_get_any_port_info (snd_seq_t * seq, int client, int port, + snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_get_any_port_info()\n"); + + return 0; +} + +/** + * \brief allocate an empty #snd_seq_port_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_port_info_malloc (snd_seq_port_info_t ** ptr) +{ + snd_seq_port_info_t *p; + + dbg_printf ("snd_seq_port_info_malloc()\n"); + + if ((p = malloc (sizeof (*p))) == NULL) + return -ENOMEM; + + *ptr = p; + + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_port_info_t + * \param pointer to object to free + */ +void +snd_seq_port_info_free (snd_seq_port_info_t * obj) +{ + free (obj); +} + +/** + * \brief allocate an empty #snd_seq_queue_tempo_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_queue_tempo_malloc (snd_seq_queue_tempo_t ** ptr) +{ + assert (ptr); + *ptr = calloc (1, sizeof (snd_seq_queue_tempo_t)); + dbg_printf ("snd_seq_queue_tempo_malloc()=%x\n", *ptr); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_tempo_t + * \param pointer to object to free + */ +void +snd_seq_queue_tempo_free (snd_seq_queue_tempo_t * obj) +{ + dbg_printf ("snd_seq_queue_tempo_free(%x)\n", obj); + free (obj); +} + +/** + * \brief Set the ppq of a queue_status container + * \param info queue_status container + * \param ppq ppq value + * + * \sa snd_seq_get_queue_tempo() + */ +void +snd_seq_queue_tempo_set_ppq (snd_seq_queue_tempo_t * info, int ppq) +{ + dbg_printf ("snd_seq_queue_tempo_set_ppq(info=%x, %d)\n", info, ppq); +} + +/** + * \brief Set the tempo of a queue_status container + * \param info queue_status container + * \param tempo tempo value + * + * \sa snd_seq_get_queue_tempo() + */ +void +snd_seq_queue_tempo_set_tempo (snd_seq_queue_tempo_t * info, + unsigned int tempo) +{ + dbg_printf ("snd_seq_queue_tempo_set_tempo(info=%x, %d)\n", info, tempo); +} + +/** + * \brief get size of #snd_seq_queue_tempo_t + * \return size in bytes + */ +size_t +snd_seq_queue_tempo_sizeof () +{ + return sizeof (snd_seq_queue_tempo_t); +} + +/** + * \brief set the queue timer information + * \param seq sequencer handle + * \param q queue id to change the timer + * \param timer timer information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_timer() + */ +int +snd_seq_set_queue_timer (snd_seq_t * seq, int q, + snd_seq_queue_timer_t * timer) +{ + dbg_printf ("snd_seq_get_queue_timer(seq=%x, q=%d, timer=%X)\n", seq, q, + timer); + return -ENXIO; // TODO +} + + +/** + * \brief Opens a new connection to the timer query interface. + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the RawMidi handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the RawMidi interface specified with + * an ASCII identifier and mode. + */ +int +snd_timer_query_open (snd_timer_query_t ** timer, const char *name, int mode) +{ + dbg_printf ("snd_timer_query_open(name=%s, mode=%x)\n", name, mode); + return -ENXIO; // TODO +} + +/** + * \brief obtain the current tempo of the queue + * \param seq sequencer handle + * \param q queue id to be queried + * \param tempo pointer to store the current tempo + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_set_queue_tempo() + */ +int +snd_seq_get_queue_tempo (snd_seq_t * seq, int q, + snd_seq_queue_tempo_t * tempo) +{ + dbg_printf ("snd_seq_get_queue_tempo(seq=%x, q=%d, tempo=%x)\n", seq, q, + tempo); + + return 0; +} + +/** + * \brief allocate an empty #snd_seq_client_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_client_info_malloc (snd_seq_client_info_t ** ptr) +{ + dbg_printf ("snd_seq_client_info_malloc()\n"); + + *ptr = malloc (sizeof (snd_seq_client_info_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_client_info_t + * \param pointer to object to free + */ +void +snd_seq_client_info_free (snd_seq_client_info_t * obj) +{ + dbg_printf ("snd_seq_client_info_free()\n"); + + free (obj); +} + +/** + * \brief Get the name of a client_info container + * \param info client_info container + * \return name string + * + * \sa snd_seq_get_client_info(), snd_seq_client_info_set_name() + */ +const char * +snd_seq_client_info_get_name (snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_client_info_get_name()\n"); + return "OSS seq client"; +} + +/** + * \brief Get the number of opened ports of a client_info container + * \param info client_info container + * \return number of opened ports + * + * \sa snd_seq_get_client_info() + */ +int +snd_seq_client_info_get_num_ports (const snd_seq_client_info_t * info) +{ + dbg_printf ("snd_seq_client_info_get_num_ports()\n"); + + return 1; +} + +/** + * \brief Get size of #snd_seq_system_info_t + * \return size in bytes + */ +size_t +snd_seq_system_info_sizeof () +{ + return sizeof (snd_seq_system_info_t); +} + + +/** + * \brief Allocate an empty #snd_seq_system_info_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_system_info_malloc (snd_seq_system_info_t ** ptr) +{ + dbg_printf ("snd_seq_system_info_malloc()\n"); + + *ptr = malloc (sizeof (snd_seq_system_info_t)); + if (*ptr == NULL) + return -ENOMEM; + return 0; +} + +/** + * \brief Frees a previously allocated #snd_seq_system_info_t + * \param pointer to object to free + */ +void +snd_seq_system_info_free (snd_seq_system_info_t * obj) +{ + free (obj); +} + +/** + * \brief obtain the sequencer system information + * \param seq sequencer handle + * \param info the pointer to be stored + * \return 0 on success otherwise a negative error code + * + * Stores the global system information of ALSA sequencer system. + * The returned data contains + * the maximum available numbers of queues, clients, ports and channels. + */ +int +snd_seq_system_info (snd_seq_t * seq, snd_seq_system_info_t * info) +{ + dbg_printf ("snd_seq_system_info()\n"); + + return 0; +} + +/** + * \brief Get maximum number of clients + * \param info #snd_seq_system_info_t container + * \return maximum number of clients + * + * \sa snd_seq_system_info() + */ +int +snd_seq_system_info_get_clients (const snd_seq_system_info_t * info) +{ + dbg_printf ("snd_seq_system_info_get_clients()\n"); + + return 4; +} + +/** + * \brief Get maximum number of queues + * \param info #snd_seq_system_info_t container + * \return maximum number of queues + * + * \sa snd_seq_system_info() + */ +int +snd_seq_system_info_get_queues (const snd_seq_system_info_t * info) +{ + dbg_printf ("snd_seq_system_info_get_queues(info=%x)\n", info); + + return 1; // TODO +} + +/** + * \brief Get maximum number of ports + * \param info #snd_seq_system_info_t container + * \return maximum number of ports + * + * \sa snd_seq_system_info() + */ +int +snd_seq_system_info_get_ports (const snd_seq_system_info_t * info) +{ + dbg_printf ("snd_seq_system_info_get_ports()\n"); + + return 4; +} + +/** + * \brief allocate a queue with the specified name + * \param seq sequencer handle + * \param name the name of the new queue + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_queue() + */ +int +snd_seq_alloc_named_queue (snd_seq_t * seq, const char *name) +{ + dbg_printf ("snd_seq_alloc_named_queue(seq=%x, name=%s)\n", seq, name); + + return 0; +} + + +/** + * \brief Get client id of a port_info container + * \param info port_info container + * \return client id + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_client() + */ +int +snd_seq_port_info_get_client (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_client()\n"); + + return 0; +} + +/** + * \brief Get the port-specified mode of a port_info container + * \param info port_info container + * \return 1 if port id is specified at creation + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_set_port_specified() + */ +int +snd_seq_port_info_get_port_specified (const snd_seq_port_info_t * info) +{ + dbg_printf ("snd_seq_port_info_get_port_specified()\n"); + + return 0; +} + +/** + * \brief Get the type bits of a port_info container + * \param info port_info container + * \return port type bits + * + * \sa snd_seq_get_port_info(), snd_seq_port_info_get_type() + */ +void +snd_seq_port_info_set_type (snd_seq_port_info_t * info, unsigned int type) +{ + dbg_printf ("snd_seq_port_info_set_type(%u)\n", type); +} + + +/** + * \brief Get the ppq of a queue_status container + * \param info queue_status container + * \return ppq value + * + * \sa snd_seq_get_queue_tempo() + */ +int +snd_seq_queue_tempo_get_ppq (const snd_seq_queue_tempo_t * info) +{ + dbg_printf ("snd_seq_queue_tempo_get_ppq()\n"); + + return 0; +} + + +/** + * \brief Get the tempo of a queue_status container + * \param info queue_status container + * \return tempo value + * + * \sa snd_seq_get_queue_tempo() + */ +unsigned int +snd_seq_queue_tempo_get_tempo (const snd_seq_queue_tempo_t * info) +{ + dbg_printf ("snd_seq_queue_tempo_get_tempo()\n"); + + return 0; +} + +/** + * \brief set the tempo of the queue + * \param seq sequencer handle + * \param q queue id to change the tempo + * \param tempo tempo information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_get_queue_tempo() + */ +int +snd_seq_set_queue_tempo (snd_seq_t * seq, int q, + snd_seq_queue_tempo_t * tempo) +{ + dbg_printf ("snd_seq_set_queue_tempo(seq=%x, q=%d, tempo=%x)\n", seq, q, + tempo); + + return 0; +} + +/** + * \brief allocate a queue + * \param seq sequencer handle + * \return the queue id (zero or positive) on success otherwise a negative error code + * + * \sa snd_seq_alloc_named_queue(), snd_seq_create_queue(), snd_seq_free_queue(), + * snd_seq_get_queue_info() + */ +int +snd_seq_alloc_queue (snd_seq_t * seq) +{ + static int queue_num = 0; + dbg_printf ("snd_seq_alloc_queue(seq=%x)=%d\n", seq, queue_num); + + return queue_num++; +} + +#define FIXED_EV(x) (_SND_SEQ_TYPE(SND_SEQ_EVFLG_FIXED) | _SND_SEQ_TYPE(x)) + +/** Event types conversion array */ +const unsigned int snd_seq_event_types[256] = { + [SND_SEQ_EVENT_SYSTEM...SND_SEQ_EVENT_RESULT] + = FIXED_EV (SND_SEQ_EVFLG_RESULT), + [SND_SEQ_EVENT_NOTE] + = + FIXED_EV (SND_SEQ_EVFLG_NOTE) | + _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_NOTE_TWOARG), + [SND_SEQ_EVENT_NOTEON...SND_SEQ_EVENT_KEYPRESS] = + FIXED_EV (SND_SEQ_EVFLG_NOTE), + [SND_SEQ_EVENT_CONTROLLER...SND_SEQ_EVENT_REGPARAM] = + FIXED_EV (SND_SEQ_EVFLG_CONTROL), + [SND_SEQ_EVENT_START...SND_SEQ_EVENT_STOP] = FIXED_EV (SND_SEQ_EVFLG_QUEUE), + [SND_SEQ_EVENT_SETPOS_TICK] + = + FIXED_EV (SND_SEQ_EVFLG_QUEUE) | + _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_TICK), + [SND_SEQ_EVENT_SETPOS_TIME] = + FIXED_EV (SND_SEQ_EVFLG_QUEUE) | + _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_TIME), + [SND_SEQ_EVENT_TEMPO...SND_SEQ_EVENT_SYNC_POS] = + FIXED_EV (SND_SEQ_EVFLG_QUEUE) | + _SND_SEQ_TYPE_OPT (SND_SEQ_EVFLG_QUEUE_VALUE), + [SND_SEQ_EVENT_TUNE_REQUEST...SND_SEQ_EVENT_SENSING] = + FIXED_EV (SND_SEQ_EVFLG_NONE), + [SND_SEQ_EVENT_ECHO...SND_SEQ_EVENT_OSS] = + FIXED_EV (SND_SEQ_EVFLG_RAW) | FIXED_EV (SND_SEQ_EVFLG_SYSTEM), + [SND_SEQ_EVENT_CLIENT_START...SND_SEQ_EVENT_PORT_CHANGE] = + FIXED_EV (SND_SEQ_EVFLG_MESSAGE), + [SND_SEQ_EVENT_PORT_SUBSCRIBED...SND_SEQ_EVENT_PORT_UNSUBSCRIBED] = + FIXED_EV (SND_SEQ_EVFLG_CONNECTION), + [SND_SEQ_EVENT_USR0...SND_SEQ_EVENT_USR9] = + FIXED_EV (SND_SEQ_EVFLG_RAW) | FIXED_EV (SND_SEQ_EVFLG_USERS), + [SND_SEQ_EVENT_SYSEX...SND_SEQ_EVENT_BOUNCE] = + _SND_SEQ_TYPE (SND_SEQ_EVFLG_VARIABLE), + [SND_SEQ_EVENT_USR_VAR0...SND_SEQ_EVENT_USR_VAR4] = + _SND_SEQ_TYPE (SND_SEQ_EVFLG_VARIABLE) | + _SND_SEQ_TYPE (SND_SEQ_EVFLG_USERS), + [SND_SEQ_EVENT_NONE] = FIXED_EV (SND_SEQ_EVFLG_NONE), +}; + +/** + * \brief obtain the running state of the queue + * \param seq sequencer handle + * \param q queue id to query + * \param status pointer to store the current status + * \return 0 on success otherwise a negative error code + * + * Obtains the running state of the specified queue q. + */ +int +snd_seq_get_queue_status (snd_seq_t * seq, int q, + snd_seq_queue_status_t * status) +{ + dbg_printf ("snd_seq_get_queue_status(seq=%x. q=%d)\n", seq, q); + + return 0; +} + +/** + * \brief allocate an empty #snd_seq_queue_status_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_queue_status_malloc (snd_seq_queue_status_t ** ptr) +{ + dbg_printf ("snd_seq_queue_status_malloc()\n"); + *ptr = calloc (1, sizeof (snd_seq_queue_status_t)); + dbg_printf ("snd_seq_queue_status_malloc()=%x\n", *ptr); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_queue_status_t + * \param pointer to object to free + */ +void +snd_seq_queue_status_free (snd_seq_queue_status_t * obj) +{ + dbg_printf ("snd_seq_queue_status_free(%x)\n", obj); + + free (obj); +} + +/** + * \brief Get the tick time of a queue_status container + * \param info queue_status container + * \return tick time + * + * \sa snd_seq_get_queue_status() + */ +snd_seq_tick_time_t +snd_seq_queue_status_get_tick_time (const snd_seq_queue_status_t * info) +{ + dbg_printf ("snd_seq_queue_status_get_tick_time(info=%x)\n", info); + + return 0; +} + +/** + * \brief get size of #snd_seq_remove_events_t + * \return size in bytes + */ +size_t +snd_seq_remove_events_sizeof () +{ + return sizeof (snd_seq_remove_events_t); +} + +/** + * \brief allocate an empty #snd_seq_remove_events_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_remove_events_malloc (snd_seq_remove_events_t ** ptr) +{ + assert (ptr); + *ptr = calloc (1, sizeof (snd_seq_remove_events_t)); + dbg_printf ("snd_seq_remove_events_malloc()=%x\n", *ptr); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_remove_events_t + * \param pointer to object to free + */ +void +snd_seq_remove_events_free (snd_seq_remove_events_t * obj) +{ + free (obj); +} + +/** + * \brief Set the removal condition bits + * \param info remove_events container + * \param flags removal condition bits + * + * \sa snd_seq_remove_events() + */ +void +snd_seq_remove_events_set_condition (snd_seq_remove_events_t * info, + unsigned int flags) +{ + dbg_printf ("snd_seq_remove_events_set_condition(rmp=%x, flags=%lu)\n", + info, flags); +} + +/** + * \brief Set the queue as removal condition + * \param info remove_events container + * \param queue queue id + * + * \sa snd_seq_remove_events() + */ +void +snd_seq_remove_events_set_queue (snd_seq_remove_events_t * info, int queue) +{ + dbg_printf ("snd_seq_remove_events_set_queue(rmp=%x, q=%d)\n", info, queue); +} + +/** + * \brief remove events on input/output buffers and pools + * \param seq sequencer handle + * \param rmp remove event container + * + * Removes matching events with the given condition from input/output buffers + * and pools. + * The removal condition is specified in \a rmp argument. + * + * \sa snd_seq_event_output(), snd_seq_drop_output(), snd_seq_reset_pool_output() + */ +int +snd_seq_remove_events (snd_seq_t * seq, snd_seq_remove_events_t * rmp) +{ + dbg_printf ("snd_seq_remove_events(seq=%x, rmp=%x)\n", seq, rmp); + + return 1; +} + + +/** + * \brief clear input buffer and and remove events in sequencer queue + * \param seq sequencer handle + * + * \sa snd_seq_drop_input_buffer(), snd_seq_remove_events() + */ +int +snd_seq_drop_input (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_drop_input(seq=%x)\n", seq); + + return 0; +} + +/** + * \brief remove all events on user-space output buffer + * \param seq sequencer handle + * + * Removes all events on user-space output buffer. + * Unlike snd_seq_drain_output(), this function doesn't remove + * events on output memory pool of sequencer. + * + * \sa snd_seq_drop_output() + */ +int +snd_seq_drop_output_buffer (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_drop_output_buffer(seq=%x)\n", seq); + + return 0; +} + +/** + * \brief extract the first event in output buffer + * \param seq sequencer handle + * \param ev_res event pointer to be extracted + * \return 0 on success otherwise a negative error code + * + * Extracts the first event in output buffer. + * If ev_res is NULL, just remove the event. + * + * \sa snd_seq_event_output() + */ +int +snd_seq_extract_output (snd_seq_t * seq, snd_seq_event_t ** ev_res) +{ + dbg_printf ("snd_seq_extract_output(seq=%x)\n", seq); + + return -EIO; +} + +/** + * \brief get size of #snd_seq_queue_status_t + * \return size in bytes + */ +size_t +snd_seq_queue_status_sizeof () +{ + return sizeof (snd_seq_queue_status_t); +} + +/** + * \brief Return the size of output buffer + * \param seq sequencer handle + * \return the size of output buffer in bytes + * + * Obtains the size of output buffer. + * This buffer is used to store decoded byte-stream of output events + * before transferring to sequencer. + * + * \sa snd_seq_set_output_buffer_size() + */ +size_t +snd_seq_get_output_buffer_size (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_get_output_buffer_size(seq=%x)\n", seq); + + return 1024; +} + +/** + * \brief Change the size of output buffer + * \param seq sequencer handle + * \param size the size of output buffer to be changed in bytes + * \return 0 on success otherwise a negative error code + * + * Changes the size of output buffer. + * + * \sa snd_seq_get_output_buffer_size() + */ +int +snd_seq_set_output_buffer_size (snd_seq_t * seq, size_t size) +{ + dbg_printf ("snd_seq_set_output_buffer_size(seq=%x, size=%d)\n", seq, size); + return 0; +} + +/** + * \brief unsubscribe a connection between ports + * \param seq sequencer handle + * \param sub subscription information to disconnect + * \return 0 on success otherwise a negative error code + * + * Unsubscribes a connection between two ports, + * described in sender and dest fields in sub argument. + * + * \sa snd_seq_subscribe_port(), snd_seq_disconnect_from(), snd_seq_disconnect_to() + */ +int +snd_seq_unsubscribe_port (snd_seq_t * seq, snd_seq_port_subscribe_t * sub) +{ + dbg_printf ("snd_seq_unsubscribe_port(seq=%x, sub=%x)\n", seq, sub); + + return 0; +} + +/** + * \brief Get the queue id of a queue_timer container + * \param info queue_timer container + * \return queue id + * + * \sa snd_seq_get_queue_timer() + */ +int +snd_seq_queue_timer_get_queue (const snd_seq_queue_timer_t * info) +{ + dbg_printf ("snd_seq_queue_timer_get_queue(timer=%x)\n", info); + + return 0; +} + +/** + * \brief obtain the queue timer information + * \param seq sequencer handle + * \param q queue id to query + * \param timer pointer to store the timer information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_set_queue_timer() + */ +int +snd_seq_get_queue_timer (snd_seq_t * seq, int q, + snd_seq_queue_timer_t * timer) +{ + dbg_printf ("snd_seq_get_queue_timer(seq=%x, q=%d, timer=%x)\n", + seq, 1, timer); + + return 0; +} + +/** + * \brief Set the timer id of a queue_timer container + * \param info queue_timer container + * \param id timer id pointer + * + * \sa snd_seq_get_queue_timer() + */ +void +snd_seq_queue_timer_set_id (snd_seq_queue_timer_t * info, + const snd_timer_id_t * id) +{ + dbg_printf ("snd_seq_queue_timer_set_id(timer=%x, id=%x)\n", info, id); +} + +/** + * \brief get size of #snd_seq_queue_timer_t + * \return size in bytes + */ +size_t +snd_seq_queue_timer_sizeof () +{ + return sizeof (snd_seq_queue_timer_t); +} + +/** + * \brief get size of #snd_seq_query_subscribe_t + * \return size in bytes + */ +size_t +snd_seq_query_subscribe_sizeof () +{ + return sizeof (snd_seq_query_subscribe_t); +} + +/** + * \brief allocate an empty #snd_seq_query_subscribe_t using standard malloc + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +int +snd_seq_query_subscribe_malloc (snd_seq_query_subscribe_t ** ptr) +{ + *ptr = calloc (1, sizeof (snd_seq_query_subscribe_t)); + + dbg_printf ("snd_seq_query_subscribe_malloc()=%x\n", *ptr); + if (!*ptr) + return -ENOMEM; + return 0; +} + +/** + * \brief frees a previously allocated #snd_seq_query_subscribe_t + * \param pointer to object to free + */ +void +snd_seq_query_subscribe_free (snd_seq_query_subscribe_t * obj) +{ + dbg_printf ("snd_seq_query_subscribe_free(obj=%x)\n", obj); + free (obj); +} + +/** + * \brief Get the address of subscriber of a query_subscribe container + * \param info query_subscribe container + * \return subscriber's address pointer + * + * \sa snd_seq_query_port_subscribers() + */ +const snd_seq_addr_t * +snd_seq_query_subscribe_get_addr (const snd_seq_query_subscribe_t * info) +{ + dbg_printf ("snd_seq_query_subscribe_get_addr(info=%x)\n", info); + + return NULL; // TODO +} + +/** + * \brief Get the index of subscriber of a query_subscribe container + * \param info query_subscribe container + * \return subscriber's index + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_index() + */ +int +snd_seq_query_subscribe_get_index (const snd_seq_query_subscribe_t * info) +{ + dbg_printf ("snd_seq_query_subscribe_get_index(info=%x)\n", info); + + return 0; // TODO +} + +/** + * \brief Set the subscriber's index to be queried + * \param info query_subscribe container + * \param index index to be queried + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_index() + */ +void +snd_seq_query_subscribe_set_index (snd_seq_query_subscribe_t * info, + int index) +{ + dbg_printf ("snd_seq_query_subscribe_t(info=%x, index=%d)\n", info, index); + + // TODO +} + +/** + * \brief Get the client/port address of a query_subscribe container + * \param info query_subscribe container + * \return client/port address pointer + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_root() + */ +const snd_seq_addr_t * +snd_seq_query_subscribe_get_root (const snd_seq_query_subscribe_t * info) +{ + dbg_printf ("snd_seq_query_subscribe_get_root(info=%x)\n", info); + + return NULL; // TODO +} + +/** + * \brief Set the client/port address of a query_subscribe container + * \param info query_subscribe container + * \param addr client/port address pointer + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_root() + */ +void +snd_seq_query_subscribe_set_root (snd_seq_query_subscribe_t * info, + const snd_seq_addr_t * addr) +{ + dbg_printf ("snd_seq_query_subscribe_set_root(info=%d, addr=%x)\n", + info, addr); +} + +/** + * \brief Get the query type of a query_subscribe container + * \param info query_subscribe container + * \return query type + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_set_type() + */ +snd_seq_query_subs_type_t +snd_seq_query_subscribe_get_type (const snd_seq_query_subscribe_t * info) +{ + dbg_printf ("snd_seq_query_subscribe_get_type(info=%x)\n", info); + + return 0; // TODO +} + +/** + * \brief Set the query type of a query_subscribe container + * \param info query_subscribe container + * \param type query type + * + * \sa snd_seq_query_port_subscribers(), snd_seq_query_subscribe_get_type() + */ +void +snd_seq_query_subscribe_set_type (snd_seq_query_subscribe_t * info, + snd_seq_query_subs_type_t type) +{ + dbg_printf ("snd_seq_query_subscribe_set_type(info=%x, type=%x)\n", + info, type); + + // TODO +} + +/** + * \brief obtain subscription information + * \param seq sequencer handle + * \param sub pointer to return the subscription information + * \return 0 on success otherwise a negative error code + * + * \sa snd_seq_subscribe_port(), snd_seq_query_port_subscribers() + */ +int +snd_seq_get_port_subscription (snd_seq_t * seq, + snd_seq_port_subscribe_t * sub) +{ + dbg_printf ("snd_seq_get_port_subscription(seq=%x, sub=%x)\n", seq, sub); + + return 0; // TODO +} + +/** + * \brief query port subscriber list + * \param seq sequencer handle + * \param subs subscription to query + * \return 0 on success otherwise a negative error code + * + * Queries the subscribers accessing to a port. + * The query information is specified in subs argument. + * + * At least, the client id, the port id, the index number and + * the query type must be set to perform a proper query. + * As the query type, #SND_SEQ_QUERY_SUBS_READ or #SND_SEQ_QUERY_SUBS_WRITE + * can be specified to check whether the readers or the writers to the port. + * To query the first subscription, set 0 to the index number. To list up + * all the subscriptions, call this function with the index numbers from 0 + * until this returns a negative value. + * + * \sa snd_seq_get_port_subscription() + */ +int +snd_seq_query_port_subscribers (snd_seq_t * seq, snd_seq_query_subscribe_t * + subs) +{ + dbg_printf ("snd_seq_query_port_subscribers(seq=%x, subs=%x)\n", seq, subs); + + return 0; // TODO +} + +/** + * \brief Get the real time of a queue_status container + * \param info queue_status container + * \param time real time + * + * \sa snd_seq_get_queue_status() + */ +const snd_seq_real_time_t * +snd_seq_queue_status_get_real_time (const snd_seq_queue_status_t * info) +{ + dbg_printf ("snd_seq_queue_status_get_real_time(info=%x)\n", info); + + return NULL; // TODO +} diff --git a/lib/libsalsa/seq_input.c b/lib/libsalsa/seq_input.c new file mode 100644 index 0000000..b61d22a --- /dev/null +++ b/lib/libsalsa/seq_input.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +static snd_seq_event_t * +alloc_event (snd_seq_t * seq) +{ + snd_seq_event_t *ev; + + if (seq->nevents >= MAX_EVENTS) + { + fprintf (stderr, "libsalsa: Local buffer overflow - event dropped\n"); + return NULL; + } + + ev = &seq->events[seq->nevents++]; + + ev->type = SND_SEQ_EVENT_SENSING; /* NOP message */ + + return ev; +} + +static void +voice_message (snd_seq_t * seq, unsigned char msg, unsigned char ch, + unsigned char *parms, int len) +{ + snd_seq_event_t *ev; + if ((ev = alloc_event (seq)) == NULL) + return; + + dbg_printf3 ("Voice message %02x, ch=%d, %3d, %3d\n", msg, ch, parms[0], + parms[1]); + + switch (msg) + { + case MIDI_NOTEON: + ev->type = SND_SEQ_EVENT_NOTEON; + ev->data.note.channel = ch; + ev->data.note.note = parms[0]; + ev->data.note.velocity = parms[1]; + break; + + case MIDI_NOTEOFF: + ev->type = SND_SEQ_EVENT_NOTEOFF; + ev->data.note.channel = ch; + ev->data.note.note = parms[0]; + ev->data.note.velocity = parms[1]; + break; + } +} + +static void +channel_message (snd_seq_t * seq, unsigned char msg, unsigned char ch, + unsigned char *parms, int len) +{ + snd_seq_event_t *ev; + if ((ev = alloc_event (seq)) == NULL) + return; + + dbg_printf3 ("Channel message %02x, ch=%d, %3d, %3d\n", msg, ch, parms[0], + parms[1]); +} + +static void +realtime_message (snd_seq_t * seq, unsigned char msg, unsigned char *parms, + int len) +{ + snd_seq_event_t *ev; + if ((ev = alloc_event (seq)) == NULL) + return; + + dbg_printf3 ("Realtime message %02x, %2x\n", msg, parms[0]); +} + +static void +sysex_message (snd_seq_t * seq, unsigned char *parms, int len) +{ + int i; + snd_seq_event_t *ev; + if ((ev = alloc_event (seq)) == NULL) + return; + + + if (alib_verbose > 2) + { + printf ("Sysex message: "); + for (i = 0; i < len; i++) + printf ("%02x ", parms[i]); + printf ("\n"); + } +} + +void +midiparser_callback (void *context, int category, unsigned char msg, + unsigned char ch, unsigned char *parms, int len) +{ + + switch (category) + { + case CAT_VOICE: + voice_message ((snd_seq_t *) context, msg, ch, parms, len); + break; + + case CAT_CHN: + channel_message ((snd_seq_t *) context, msg, ch, parms, len); + break; + + case CAT_REALTIME: + realtime_message ((snd_seq_t *) context, msg, parms, len); + break; + + case CAT_SYSEX: + sysex_message ((snd_seq_t *) context, parms, len); + break; + + case CAT_MTC: + default: + dbg_printf ("Unknown MIDI message category %d\n", category); + } +} diff --git a/lib/libsalsa/seq_output.c b/lib/libsalsa/seq_output.c new file mode 100644 index 0000000..6170dc2 --- /dev/null +++ b/lib/libsalsa/seq_output.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +static int +midi_out3 (snd_seq_t * seq, int msg, int parm1, int parm2) +{ + unsigned char buf[3]; + int l; + + if (msg < 0 || msg >= 0xff) + return -ERANGE; + if (parm1 < 0 || parm1 > 0x7f) + return -ERANGE; + if (parm2 < 0 || parm2 > 0x7f) + return -ERANGE; + + buf[0] = msg; + buf[1] = parm1; + buf[2] = parm2; + + if ((l = write (seq->fd, buf, 3)) != 3) + { + if (l == -1) + return -errno; + + return -EBADE; /* Randomly selected error */ + } + + return 0; +} + +static int +midi_out2 (snd_seq_t * seq, int msg, int parm1) +{ + unsigned char buf[3]; + int l; + + if (msg < 0 || msg >= 0xff) + return -ERANGE; + if (parm1 < 0 || parm1 > 0x7f) + return -ERANGE; + + buf[0] = msg; + buf[1] = parm1; + + if ((l = write (seq->fd, buf, 2)) != 2) + { + if (l == -1) + return -errno; + + return -EBADE; /* Randomly selected error */ + } + + return 0; +} + +int +convert_event (snd_seq_t * seq, snd_seq_event_t * ev) +{ + int value; + + dbg_printf3 + ("Event %2d: flags=%08x tag=%08x, q=%2d, time=%d, src=%x, dst=%x\n", + ev->type, ev->flags, ev->tag, ev->queue, ev->time, ev->source, ev->dest); + + switch (ev->type) + { + case SND_SEQ_EVENT_CONTROLLER: + dbg_printf3 ("\tSND_SEQ_EVENT_CONTRLLER %2d, %3d, %3d\n", + ev->data.control.channel, + ev->data.control.param, ev->data.control.value); + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0xB0 + ev->data.control.channel, + ev->data.control.param, ev->data.control.value); + break; + + case SND_SEQ_EVENT_PGMCHANGE: + dbg_printf3 ("\tSND_SEQ_EVENT_PGMCHANGE %2d, %3d, %3d\n", + ev->data.control.channel, + ev->data.control.param, ev->data.control.value); + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out2 (seq, 0xC0 + ev->data.control.channel, + ev->data.control.value); + break; + + case SND_SEQ_EVENT_CHANPRESS: + dbg_printf3 ("\tSND_SEQ_EVENT_CHANPRESS %2d, %5d\n", + ev->data.control.channel, ev->data.control.value); + value = ev->data.control.value + 8192; + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0xD0 + ev->data.control.channel, + value & 0x7f, (value >> 7) & 0x7f); + break; + + case SND_SEQ_EVENT_PITCHBEND: + dbg_printf3 ("\tSND_SEQ_EVENT_PITCHBEND %2d, %5d\n", + ev->data.control.channel, ev->data.control.value); + value = ev->data.control.value + 8192; + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0xE0 + ev->data.control.channel, + value & 0x7f, (value >> 7) & 0x7f); + break; + + case SND_SEQ_EVENT_NOTEON: + dbg_printf3 ("\tSND_SEQ_EVENT_NOTEON %2d, %3d, %d\n", + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0x90 + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + break; + + case SND_SEQ_EVENT_NOTEOFF: + dbg_printf3 ("\tSND_SEQ_EVENT_NOTEOFF %2d, %3d, %d\n", + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0x80 + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + break; + + case SND_SEQ_EVENT_KEYPRESS: + dbg_printf3 ("\tSND_SEQ_EVENT_KEYPRESS %2d, %3d, %d\n", + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + if (ev->data.control.channel > 15) + return -ERANGE; + return midi_out3 (seq, 0xA0 + ev->data.note.channel, + ev->data.note.note, ev->data.note.velocity); + break; + + case SND_SEQ_EVENT_SYSTEM: + dbg_printf ("\tSND_SEQ_EVENT_SYSTEM\n"); + break; + case SND_SEQ_EVENT_RESULT: + dbg_printf ("\tSND_SEQ_EVENT_RESULT\n"); + break; + case SND_SEQ_EVENT_NOTE: + dbg_printf ("\tSND_SEQ_EVENT_NOTE\n"); + break; + case SND_SEQ_EVENT_CONTROL14: + dbg_printf ("\tSND_SEQ_EVENT_CONTROL14\n"); + break; + case SND_SEQ_EVENT_NONREGPARAM: + dbg_printf ("\tSND_SEQ_EVENT_NONREGPARAM\n"); + break; + case SND_SEQ_EVENT_REGPARAM: + dbg_printf ("\tSND_SEQ_EVENT_REGPARAM\n"); + break; + case SND_SEQ_EVENT_SONGPOS: + dbg_printf ("\tSND_SEQ_EVENT_SONGPOS\n"); + break; + case SND_SEQ_EVENT_SONGSEL: + dbg_printf ("\tSND_SEQ_EVENT_SONGSEL\n"); + break; + case SND_SEQ_EVENT_QFRAME: + dbg_printf ("\tSND_SEQ_EVENT_QFRAME\n"); + break; + case SND_SEQ_EVENT_TIMESIGN: + dbg_printf ("\tSND_SEQ_EVENT_TIMESIGN\n"); + break; + case SND_SEQ_EVENT_KEYSIGN: + dbg_printf ("\tSND_SEQ_EVENT_KEYSIGN\n"); + break; + case SND_SEQ_EVENT_START: + dbg_printf ("\tSND_SEQ_EVENT_START\n"); + break; + case SND_SEQ_EVENT_CONTINUE: + dbg_printf ("\tSND_SEQ_EVENT_CONTINUE\n"); + break; + case SND_SEQ_EVENT_STOP: + dbg_printf ("\tSND_SEQ_EVENT_STOP\n"); + break; + case SND_SEQ_EVENT_SETPOS_TICK: + dbg_printf ("\tSND_SEQ_EVENT_SETPOS_TICK\n"); + break; + case SND_SEQ_EVENT_SETPOS_TIME: + dbg_printf ("\tSND_SEQ_EVENT_SETPOS_TIME\n"); + break; + case SND_SEQ_EVENT_TEMPO: + dbg_printf ("\tSND_SEQ_EVENT_TEMPO\n"); + break; + case SND_SEQ_EVENT_CLOCK: + dbg_printf ("\tSND_SEQ_EVENT_CLOCK\n"); + break; + case SND_SEQ_EVENT_TICK: + dbg_printf ("\tSND_SEQ_EVENT_TICK\n"); + break; + case SND_SEQ_EVENT_QUEUE_SKEW: + dbg_printf ("\tSND_SEQ_EVENT_QUEUE_SKEW\n"); + break; + case SND_SEQ_EVENT_SYNC_POS: + dbg_printf ("\tSND_SEQ_EVENT_SYNC_POS\n"); + break; + case SND_SEQ_EVENT_TUNE_REQUEST: + dbg_printf ("\tSND_SEQ_EVENT_TUNE_REQUEST\n"); + break; + case SND_SEQ_EVENT_RESET: + dbg_printf ("\tSND_SEQ_EVENT_RESET\n"); + break; + case SND_SEQ_EVENT_SENSING: + dbg_printf ("\tSND_SEQ_EVENT_SENSING\n"); + break; + case SND_SEQ_EVENT_ECHO: + dbg_printf ("\tSND_SEQ_EVENT_ECHO\n"); + break; + case SND_SEQ_EVENT_OSS: + dbg_printf ("\tSND_SEQ_EVENT_OSS\n"); + break; + case SND_SEQ_EVENT_CLIENT_START: + dbg_printf ("\tSND_SEQ_EVENT_CLIENT_START\n"); + break; + case SND_SEQ_EVENT_CLIENT_EXIT: + dbg_printf ("\tSND_SEQ_EVENT_CLIENT_EXIT\n"); + break; + case SND_SEQ_EVENT_CLIENT_CHANGE: + dbg_printf ("\tSND_SEQ_EVENT_CLIENT_CHANGE\n"); + break; + case SND_SEQ_EVENT_PORT_START: + dbg_printf ("\tSND_SEQ_EVENT_PORT_START\n"); + break; + case SND_SEQ_EVENT_PORT_EXIT: + dbg_printf ("\tSND_SEQ_EVENT_PORT_EXIT\n"); + break; + case SND_SEQ_EVENT_PORT_CHANGE: + dbg_printf ("\tSND_SEQ_EVENT_PORT_CHANGE\n"); + break; + case SND_SEQ_EVENT_PORT_SUBSCRIBED: + dbg_printf ("\tSND_SEQ_EVENT_PORT_SUBSCRIBED\n"); + break; + case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: + dbg_printf ("\tSND_SEQ_EVENT_PORT_UNSUBSCRIBED\n"); + break; + case SND_SEQ_EVENT_USR0: + dbg_printf ("\tSND_SEQ_EVENT_USR0\n"); + break; + case SND_SEQ_EVENT_USR1: + dbg_printf ("\tSND_SEQ_EVENT_USR1\n"); + break; + case SND_SEQ_EVENT_USR2: + dbg_printf ("\tSND_SEQ_EVENT_USR2\n"); + break; + case SND_SEQ_EVENT_USR3: + dbg_printf ("\tSND_SEQ_EVENT_USR3\n"); + break; + case SND_SEQ_EVENT_USR4: + dbg_printf ("\tSND_SEQ_EVENT_USR4\n"); + break; + case SND_SEQ_EVENT_USR5: + dbg_printf ("\tSND_SEQ_EVENT_USR5\n"); + break; + case SND_SEQ_EVENT_USR6: + dbg_printf ("\tSND_SEQ_EVENT_USR6\n"); + break; + case SND_SEQ_EVENT_USR7: + dbg_printf ("\tSND_SEQ_EVENT_USR7\n"); + break; + case SND_SEQ_EVENT_USR8: + dbg_printf ("\tSND_SEQ_EVENT_USR8\n"); + break; + case SND_SEQ_EVENT_USR9: + dbg_printf ("\tSND_SEQ_EVENT_USR9\n"); + break; + case SND_SEQ_EVENT_SYSEX: + dbg_printf ("\tSND_SEQ_EVENT_SYSEX\n"); + break; + case SND_SEQ_EVENT_BOUNCE: + dbg_printf ("\tSND_SEQ_EVENT_BOUNCE\n"); + break; + case SND_SEQ_EVENT_USR_VAR0: + dbg_printf ("\tSND_SEQ_EVENT_USR_VAR0\n"); + break; + case SND_SEQ_EVENT_USR_VAR1: + dbg_printf ("\tSND_SEQ_EVENT_USR_VAR1\n"); + break; + case SND_SEQ_EVENT_USR_VAR2: + dbg_printf ("\tSND_SEQ_EVENT_USR_VAR2\n"); + break; + case SND_SEQ_EVENT_USR_VAR3: + dbg_printf ("\tSND_SEQ_EVENT_USR_VAR3\n"); + break; + case SND_SEQ_EVENT_USR_VAR4: + dbg_printf ("\tSND_SEQ_EVENT_USR_VAR4\n"); + break; + case SND_SEQ_EVENT_NONE: + dbg_printf ("\tSND_SEQ_EVENT_NONE\n"); + break; + default: + dbg_printf ("\tUnknown event type %d\n", ev->type); + } + return 0; +} diff --git a/lib/libsalsa/seqmid.c b/lib/libsalsa/seqmid.c new file mode 100644 index 0000000..e3ad1d0 --- /dev/null +++ b/lib/libsalsa/seqmid.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +/** + * \brief create a port - simple version + * \param seq sequencer handle + * \param name the name of the port + * \param caps capability bits + * \param type type bits + * \return the created port number or negative error code + * + * Creates a port with the given capability and type bits. + * + * \sa snd_seq_create_port(), snd_seq_delete_simple_port() + */ +int +snd_seq_create_simple_port (snd_seq_t * seq, const char *name, + unsigned int caps, unsigned int type) +{ + snd_seq_port_info_t pinfo; + int result; + + dbg_printf + ("snd_seq_create_simple_port(seq=%x, name='%s', caps=%x, type=%x)\n", seq, + name, caps, type); + + memset (&pinfo, 0, sizeof (pinfo)); + if (name) + strncpy (pinfo.name, name, sizeof (pinfo.name) - 1); + pinfo.capability = caps; + pinfo.type = type; + pinfo.midi_channels = 16; + pinfo.midi_voices = 64; /* XXX */ + pinfo.synth_voices = 0; /* XXX */ + + result = snd_seq_create_port (seq, &pinfo); + if (result < 0) + return result; + else + return pinfo.port; +} + +/** + * \brief delete the port + * \param seq sequencer handle + * \param port port id + * \return 0 on success or negative error code + * + * \sa snd_seq_delete_port(), snd_seq_create_simple_port() + */ +int +snd_seq_delete_simple_port (snd_seq_t * seq, int port) +{ + dbg_printf ("snd_seq_delete_simple_port()\n"); + + return 0; +} + +/** + * \brief set client name + * \param seq sequencer handle + * \param name name string + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_info() + */ +int +snd_seq_set_client_name (snd_seq_t * seq, const char *name) +{ + snd_seq_client_info_t info; + int err; + + dbg_printf ("snd_seq_set_client_name(seq=%x, name='%s')\n", seq, name); + + if ((err = snd_seq_get_client_info (seq, &info)) < 0) + return err; + strncpy (info.name, name, sizeof (info.name) - 1); + return snd_seq_set_client_info (seq, &info); +} + +/** + * \brief change the output pool size of the given client + * \param seq sequencer handle + * \param size output pool size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int +snd_seq_set_client_pool_output (snd_seq_t * seq, size_t size) +{ + dbg_printf ("snd_seq_set_client_pool_output(seq=%x, size=%d)\n", seq, size); + return 0; +} + +/** + * \brief parse the given string and get the sequencer address + * \param seq sequencer handle + * \param addr the address pointer to be returned + * \param arg the string to be parsed + * \return 0 on success or negative error code + * + * This function parses the sequencer client and port numbers from the given string. + * The client and port tokes are separated by either colon or period, e.g. 128:1. + * When \a seq is not NULL, the function accepts also a client name not only + * digit numbers. + */ +int +snd_seq_parse_address (snd_seq_t * seq, snd_seq_addr_t * addr, + const char *arg) +{ + dbg_printf ("snd_seq_parse_address()\n"); + + return 0; +} + +/** + * \brief wait until all events are processed + * \param seq sequencer handle + * \return 0 on success or negative error code + * + * This function waits until all events of this client are processed. + * + * \sa snd_seq_drain_output() + */ +int +snd_seq_sync_output_queue (snd_seq_t * seq) +{ + dbg_printf ("snd_seq_sync_output_queue()\n"); + + return 0; +} + +/** + * \brief simple disconnection + * \param myport the port id as sender + * \param dest_client destination client id + * \param dest_port destination port id + * \return 0 on success or negative error code + * + * Remove connection from the given sender client:port + * to the given destination port in the current client. + * + * \sa snd_seq_unsubscribe_port(), snd_seq_connect_to() + */ +int +snd_seq_disconnect_to (snd_seq_t * seq, int myport, int dest_client, + int dest_port) +{ + dbg_printf + ("snd_seq_disconnect_to(seq=%x, myport=%d, dest_client=%d, dest_port=%d)\n", + seq, myport, dest_client, dest_port); + + return 0; +} + +/** + * \brief change the input pool size of the given client + * \param seq sequencer handle + * \param size input pool size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int +snd_seq_set_client_pool_input (snd_seq_t * seq, size_t size) +{ + dbg_printf ("snd_seq_set_client_pool_input(seq=%x, size=%d)\n", seq, size); + + return 0; +} + +/** + * \brief change the output room size of the given client + * \param seq sequencer handle + * \param size output room size + * \return 0 on success or negative error code + * + * \sa snd_seq_set_client_pool() + */ +int +snd_seq_set_client_pool_output_room (snd_seq_t * seq, size_t size) +{ + dbg_printf ("snd_seq_set_client_pool_output_room(seq=%x, size=%d)\n", seq, + size); + + return 0; +} diff --git a/lib/libsalsa/stubs.c b/lib/libsalsa/stubs.c new file mode 100644 index 0000000..f13771f --- /dev/null +++ b/lib/libsalsa/stubs.c @@ -0,0 +1,59 @@ +#include <stdio.h> +extern int alib_verbose; + +#define STUB(x) \ +int x(void) \ +{ \ + if (alib_verbose>0)printf("libsalsa: Stub for " #x " called.\n"); \ + return -53; \ +} + +#define STUB_NULL(x) \ +void* x(void) \ +{ \ + if (alib_verbose>0)printf("libsalsa: Stub for " #x " called.\n"); \ + return (void*)0; \ +} + +STUB (snd_ctl_elem_info_get_count) +STUB (snd_hctl_elem_write) +STUB (snd_hctl_first_elem) +STUB (snd_ctl_elem_info_get_item_name) +STUB (snd_hctl_elem_get_callback_private) +STUB_NULL (snd_ctl_card_info_get_driver) +STUB (snd_ctl_elem_value_get_enumerated) +STUB (snd_hctl_set_callback) +STUB (snd_ctl_elem_info_set_item) +STUB (snd_hctl_load) +STUB (snd_ctl_elem_info_get_step) +STUB (snd_ctl_elem_value_set_enumerated) +STUB (snd_ctl_elem_info_get_name) +STUB (snd_hctl_handle_events) +STUB (snd_ctl_elem_info_sizeof) +STUB (snd_ctl_elem_value_get_boolean) +STUB (snd_ctl_elem_value_malloc) +STUB (snd_ctl_elem_id_set_index) +STUB (snd_ctl_elem_value_get_integer) +STUB (snd_hctl_nonblock) +STUB (snd_hctl_get_count) +STUB (snd_ctl_card_info_get_longname) +STUB (snd_hctl_elem_next) +STUB (snd_ctl_elem_info_get_index) +STUB (snd_hctl_elem_read) +STUB (snd_hctl_find_elem) +STUB (snd_ctl_elem_value_set_integer) +STUB (snd_hctl_elem_set_callback) +STUB (snd_hctl_poll_descriptors) +STUB (snd_ctl_elem_info_get_items) +STUB (snd_ctl_elem_info_get_max) +STUB (snd_hctl_open) +STUB (snd_ctl_elem_value_set_boolean) +STUB (snd_ctl_elem_id_set_interface) +STUB (snd_hctl_set_callback_private) +STUB (snd_ctl_elem_id_sizeof) +STUB (snd_ctl_elem_info_get_type) +STUB (snd_hctl_close) +STUB (snd_ctl_elem_info_malloc) +STUB (snd_ctl_elem_info_get_min) +STUB (snd_hctl_elem_info) +STUB (snd_hctl_elem_set_callback_private) STUB (snd_ctl_elem_id_set_name) diff --git a/lib/libsalsa/timer.c b/lib/libsalsa/timer.c new file mode 100644 index 0000000..3ea5da6 --- /dev/null +++ b/lib/libsalsa/timer.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2004 by Hannu Savolainen < hannu@opensound.com> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include <stdio.h> +#include "local.h" + +struct _snd_timer +{ + int dummy; +}; + +struct _snd_timer_id +{ + int dummy; +}; + +struct _snd_timer_info +{ + int dummy; +}; + +/** + * \brief Opens a new connection to the timer interface. + * \param timer Returned handle (NULL if not wanted) + * \param name ASCII identifier of the timer handle + * \param mode Open mode + * \return 0 on success otherwise a negative error code + * + * Opens a new connection to the timer interface specified with + * an ASCII identifier and mode. + */ +int +snd_timer_open (snd_timer_t ** tmr, const char *name, int mode) +{ + snd_timer_t *timer; + + ALIB_INIT (); + if (!alib_appcheck ()) + { + dbg_printf ("snd_timer_open(%s, %x) refused,\n", name, mode); + return -ENODEV; + } + + timer = malloc (sizeof (*timer)); + + dbg_printf ("snd_timer_open(name='%s', mode=%x)=%x\n", name, mode, timer); + + if (timer == NULL) + return -ENOMEM; + + *tmr = timer; + + return 0; +} + +/** + * \brief close timer handle + * \param timer timer handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified timer handle and frees all associated + * resources. + */ +int +snd_timer_close (snd_timer_t * timer) +{ + dbg_printf ("snd_timer_close(%x)\n", timer); + + free (timer); + return 0; +} + +/** + * \brief get size of the snd_timer_id_t structure in bytes + * \return size of the snd_timer_id_t structure in bytes + */ +size_t +snd_timer_id_sizeof () +{ + return sizeof (snd_timer_id_t); +} + +/** + * \brief get timer card + * \param params pointer to #snd_timer_id_t structure + * \return timer card number + */ +int +snd_timer_id_get_card (snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_id_get_card(tid=%x)\n", tid); + + return 0; // TODO +} + +/** + * \brief get timer class + * \param tid pointer to #snd_timer_id_t structure + * \return timer class + */ +int +snd_timer_id_get_class (snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_id_get_class(tid=%x)\n", tid); + + return 0; // TODO +} + + +/** + * \brief get timer device + * \param params pointer to #snd_timer_id_t structure + * \return timer device number + */ +int +snd_timer_id_get_device (snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_id_get_device(tid=%x)\n", tid); + + return 0; // TODO +} + +/** + * \brief get timer sub-class + * \param params pointer to #snd_timer_id_t structure + * \return timer sub-class + */ +int +snd_timer_id_get_sclass (snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_id_get_sclass(tid=%x)\n", tid); + + return 0; // TODO +} + +/** + * \brief get timer subdevice + * \param params pointer to #snd_timer_id_t structure + * \return timer subdevice number + */ +int +snd_timer_id_get_subdevice (snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_id_get_subdevice(tid=%x)\n", tid); + + return 0; // TODO +} + +/** + * \brief set timer card + * \param tid pointer to #snd_timer_id_t structure + * \param card card number + */ +void +snd_timer_id_set_card (snd_timer_id_t * tid, int card) +{ + dbg_printf ("snd_timer_id_set_card(tid=%x, card=%d)\n", tid, card); + + // TODO +} + +/** + * \brief set timer class + * \param tid pointer to #snd_timer_id_t structure + * \param dev_class class of timer device + */ +void +snd_timer_id_set_class (snd_timer_id_t * tid, int dev_class) +{ + dbg_printf ("snd_timer_id_set_class(tid=%x, dev_class=%d)\n", tid, + dev_class); + // TODO +} + +/** + * \brief set timer device + * \param tid pointer to #snd_timer_id_t structure + * \param device device number + */ +void +snd_timer_id_set_device (snd_timer_id_t * tid, int device) +{ + dbg_printf ("snd_timer_id_set_device(tid=%x, device=%d)\n", tid, device); + + // TODO +} + +/** + * \brief set timer sub-class + * \param tid pointer to #snd_timer_id_t structure + * \param dev_sclass sub-class of timer device + */ +void +snd_timer_id_set_sclass (snd_timer_id_t * tid, int dev_sclass) +{ + dbg_printf ("snd_timer_id_set_sclass(tid=%x, dev_sclass=%d)\n", + tid, dev_sclass); + // TODO +} + +/** + * \brief set timer subdevice + * \param tid pointer to #snd_timer_id_t structure + * \param subdevice subdevice number + */ +void +snd_timer_id_set_subdevice (snd_timer_id_t * tid, int subdevice) +{ + dbg_printf ("snd_timer_id_set_subdevice(tid=%x, subdevice=%d)\n", + tid, subdevice); + + // TODO +} + +/** + * \brief get size of the snd_timer_info_t structure in bytes + * \return size of the snd_timer_info_t structure in bytes + */ +size_t +snd_timer_info_sizeof () +{ + return sizeof (snd_timer_info_t); +} + +/** + * \brief allocate a new snd_timer_info_t structure + * \param ptr returned pointer + * \return 0 on success otherwise a negative error code if fails + * + * Allocates a new snd_timer_info_t structure using the standard + * malloc C library function. + */ +int +snd_timer_info_malloc (snd_timer_info_t ** info) +{ + *info = calloc (1, sizeof (snd_timer_info_t)); + dbg_printf ("snd_timer_info_malloc()=%x\n", *info); + if (!*info) + return -ENOMEM; + return 0; +} + +/** + * \brief frees the snd_timer_info_t structure + * \param info pointer to the snd_timer_info_t structure to free + * + * Frees the given snd_timer_info_t structure using the standard + * free C library function. + */ +void +snd_timer_info_free (snd_timer_info_t * info) +{ + dbg_printf ("snd_timer_info_free(%x)\n", info); + free (info); +} + +/** + * \brief get information about timer handle + * \param timer timer handle + * \param info pointer to a snd_timer_info_t structure to be filled + * \return 0 on success otherwise a negative error code + */ +int +snd_timer_info (snd_timer_t * timer, snd_timer_info_t * info) +{ + dbg_printf ("snd_timer_info(timer=%x, info=%x)\n", timer, info); + + // TODO + + return 0; +} + +/** + * \brief get timer name + * \param info pointer to #snd_timer_info_t structure + * \return timer name + */ +const char * +snd_timer_info_get_name (snd_timer_info_t * info) +{ + dbg_printf ("snd_timer_info_get_name(info=%x)\n", info); + + return "OSS Timer"; // TODO +} + + +/** + * \brief get timer resolution in us + * \param info pointer to #snd_timer_info_t structure + * \return timer resolution + */ +long +snd_timer_info_get_resolution (snd_timer_info_t * info) +{ + dbg_printf ("snd_timer_info_get_resolution(info=%x)\n", info); + + return 1000; // TODO +} + + +static int +snd_timer_query_open_conf (snd_timer_query_t ** timer, + const char *name, snd_config_t * timer_root, + snd_config_t * timer_conf, int mode) +{ + dbg_printf + ("snd_timer_query_open_conf(name='%s', root=%x, conf=%x, mode=%x)\n", + name, timer_root, timer_conf, mode); + ALIB_INIT (); + if (!alib_appcheck ()) + return -ENODEV; + + return -EIO; +} + +/** + * \brief close timer query handle + * \param timer timer handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified timer handle and frees all associated + * resources. + */ +int +snd_timer_query_close (snd_timer_query_t * timer) +{ + dbg_printf ("snd_timer_query_close(timer=%x)\n", timer); + + return 0; +} + +/** + * \brief obtain the next timer identification + * \param timer timer handle + * \param tid timer identification + * \return 0 on success otherwise a negative error code + * + * if tid->dev_class is -1, then the first device is returned + * if result tid->dev_class is -1, no more devices are left + */ +int +snd_timer_query_next_device (snd_timer_query_t * timer, snd_timer_id_t * tid) +{ + dbg_printf ("snd_timer_query_next_device(timer=%x, tid=%x)\n", timer, tid); + + return -1; +} |