├── .gitignore ├── COPYING ├── COPYING.GPL ├── Makefile.am ├── a52 ├── 60-a52-encoder.conf ├── Makefile.am └── pcm_a52.c ├── aaf ├── Makefile.am └── pcm_aaf.c ├── acinclude.m4 ├── arcam-av ├── 50-arcam-av-ctl.conf ├── Makefile.am ├── arcam_av.c ├── arcam_av.h └── ctl_arcam_av.c ├── configure.ac ├── cvscompile ├── doc ├── Makefile.am ├── README-arcam-av ├── README-jack ├── README-maemo ├── README-pcm-oss ├── README-pulse ├── a52.txt ├── aaf.txt ├── lavrate.txt ├── samplerate.txt ├── speexdsp.txt ├── speexrate.txt ├── upmix.txt └── vdownmix.txt ├── gitcompile ├── install-hooks.am ├── jack ├── 50-jack.conf ├── Makefile.am └── pcm_jack.c ├── m4 └── attributes.m4 ├── maemo ├── 98-maemo.conf ├── Makefile.am ├── alsa-dsp.c ├── constants.h ├── debug.h ├── dsp-ctl.c ├── dsp-protocol.c ├── dsp-protocol.h ├── list.h ├── reporting.h └── types.h ├── mix ├── 60-upmix.conf ├── 60-vdownmix.conf ├── Makefile.am ├── pcm_upmix.c └── pcm_vdownmix.c ├── oss ├── 50-oss.conf ├── Makefile.am ├── ctl_oss.c └── pcm_oss.c ├── pph ├── 10-speexrate.conf ├── Makefile.am ├── arch.h ├── fixed_generic.h ├── rate_speexrate.c ├── resample.c └── speex_resampler.h ├── pulse ├── 50-pulseaudio.conf ├── 99-pulseaudio-default.conf.example ├── Makefile.am ├── conf_pulse.c ├── ctl_pulse.c ├── pcm_pulse.c ├── pulse.c └── pulse.h ├── rate-lav ├── 10-rate-lav.conf ├── Makefile.am ├── gcd.h └── rate_lavrate.c ├── rate ├── 10-samplerate.conf ├── Makefile.am └── rate_samplerate.c ├── speex ├── 60-speex.conf ├── Makefile.am └── pcm_speex.c └── usb_stream ├── 98-usb-stream.conf ├── Makefile.am ├── pcm_usb_stream.c └── usb_stream.h /.gitignore: -------------------------------------------------------------------------------- 1 | configure 2 | config.log 3 | config.cache 4 | config.status 5 | config.guess 6 | config.sub 7 | config.h 8 | confdefs.h 9 | config.h.in 10 | Makefile 11 | Makefile.in 12 | libtool 13 | depcomp 14 | ltmain.sh 15 | ltconfig 16 | version 17 | aclocal.m4 18 | mkinstalldirs 19 | install-sh 20 | missing 21 | autom4te.cache 22 | depcomp 23 | compile 24 | stamp-h1 25 | .libs 26 | .deps 27 | *.la 28 | *.lo 29 | *.orig 30 | *.rej 31 | *~ 32 | /m4/libtool.m4 33 | /m4/lt~obsolete.m4 34 | /m4/ltoptions.m4 35 | /m4/ltsugar.m4 36 | /m4/ltversion.m4 37 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = doc 2 | if HAVE_OSS 3 | SUBDIRS += oss 4 | endif 5 | if HAVE_MIX 6 | SUBDIRS += mix 7 | endif 8 | if HAVE_JACK 9 | SUBDIRS += jack 10 | endif 11 | if HAVE_PULSE 12 | SUBDIRS += pulse 13 | endif 14 | if HAVE_SAMPLERATE 15 | SUBDIRS += rate 16 | endif 17 | if HAVE_A52 18 | SUBDIRS += a52 19 | endif 20 | if HAVE_LAVRATE 21 | SUBDIRS += rate-lav 22 | endif 23 | if HAVE_USBSTREAM 24 | SUBDIRS += usb_stream 25 | endif 26 | if HAVE_ARCAMAV 27 | SUBDIRS += arcam-av 28 | endif 29 | if HAVE_MAEMO_PLUGIN 30 | SUBDIRS += maemo 31 | endif 32 | if HAVE_PPH 33 | SUBDIRS += pph 34 | endif 35 | if HAVE_SPEEXDSP 36 | SUBDIRS += speex 37 | endif 38 | if HAVE_AAF 39 | SUBDIRS += aaf 40 | endif 41 | 42 | EXTRA_DIST = gitcompile version COPYING.GPL m4/attributes.m4 43 | AUTOMAKE_OPTIONS = foreign 44 | ACLOCAL_AMFLAGS = -I m4 45 | 46 | dist-hook: 47 | -chmod -R a+r $(distdir) 48 | @if ! test -z "$(AMTAR)"; then \ 49 | $(AMTAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ 50 | else \ 51 | $(TAR) --create --verbose --file=- $(distdir) | bzip2 -c -9 > $(distdir).tar.bz2 ; \ 52 | fi 53 | -------------------------------------------------------------------------------- /a52/60-a52-encoder.conf: -------------------------------------------------------------------------------- 1 | pcm.a52 { 2 | @args [ CARD SLAVE RATE BITRATE CHANNELS ] 3 | @args.CARD { 4 | type integer 5 | default { 6 | @func refer 7 | name defaults.pcm.card 8 | } 9 | } 10 | @args.SLAVE { 11 | type string 12 | } 13 | @args.RATE { 14 | type integer 15 | default 48000 16 | } 17 | @args.BITRATE { 18 | type integer 19 | default 448 20 | } 21 | @args.CHANNELS { 22 | type string 23 | default 6 24 | } 25 | type a52 26 | card $CARD 27 | slavepcm $SLAVE 28 | rate $RATE 29 | bitrate $BITRATE 30 | channels $CHANNELS 31 | hint { 32 | show { 33 | @func refer 34 | name defaults.namehint.basic 35 | } 36 | description "Plugin to convert multichannel stream to A52 (AC3) bitstream" 37 | } 38 | } 39 | 40 | # 41 | # A quick test command: 42 | # CARD=1 # replace with your IEC958 card 43 | # DEVICE=1 # replace with your IEC958 PCM device number 44 | # speaker-test -d -b 2000000 -c 6 -D"plug:{SLAVE=\"a52:${CARD},'hw:${CARD},${DEVICE}'\"}" 45 | # 46 | -------------------------------------------------------------------------------- /a52/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 60-a52-encoder.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_a52_LTLIBRARIES = libasound_module_pcm_a52.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_pcm_a52dir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @LIBAV_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_pcm_a52_la_SOURCES = pcm_a52.c 15 | libasound_module_pcm_a52_la_LIBADD = @ALSA_LIBS@ @LIBAV_LIBS@ @LIBAV_CODEC_LIBS@ 16 | 17 | include ../install-hooks.am 18 | 19 | install-data-hook: install-conf-hook 20 | 21 | uninstall-local: uninstall-conf-hook 22 | -------------------------------------------------------------------------------- /aaf/Makefile.am: -------------------------------------------------------------------------------- 1 | asound_module_pcm_aaf_LTLIBRARIES = libasound_module_pcm_aaf.la 2 | 3 | asound_module_pcm_aafdir = @ALSA_PLUGIN_DIR@ 4 | 5 | AM_CFLAGS = @ALSA_CFLAGS@ @AVTP_CFLAGS@ 6 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 7 | 8 | libasound_module_pcm_aaf_la_SOURCES = pcm_aaf.c 9 | libasound_module_pcm_aaf_la_LIBADD = @ALSA_LIBS@ @AVTP_LIBS@ 10 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | AC_DEFUN([SAVE_PLUGINS_VERSION], [ 2 | AC_MSG_CHECKING(for plugins version) 3 | SND_PLUGINS_VERSION=$VERSION 4 | echo $VERSION > $srcdir/version 5 | AC_MSG_RESULT($SND_PLUGINS_VERSION) 6 | ]) 7 | -------------------------------------------------------------------------------- /arcam-av/50-arcam-av-ctl.conf: -------------------------------------------------------------------------------- 1 | ctl.arcam_av { 2 | @args [ PORT ] 3 | @args.PORT { 4 | type string 5 | default "/dev/ttyUSB0" 6 | } 7 | type arcam_av 8 | port $PORT 9 | hint { 10 | show { 11 | @func refer 12 | name defaults.namehint.basic 13 | } 14 | description "Arcam-AV Amplifier" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /arcam-av/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 50-arcam-av-ctl.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_ctl_arcam_av_LTLIBRARIES = libasound_module_ctl_arcam_av.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_ctl_arcam_avdir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined 13 | 14 | libasound_module_ctl_arcam_av_la_SOURCES = ctl_arcam_av.c arcam_av.c arcam_av.h 15 | libasound_module_ctl_arcam_av_la_LIBADD = @ALSA_LIBS@ -lpthread 16 | 17 | include ../install-hooks.am 18 | 19 | install-data-hook: install-conf-hook 20 | 21 | uninstall-local: uninstall-conf-hook 22 | -------------------------------------------------------------------------------- /arcam-av/arcam_av.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ALSA -> Arcam AV control plugin 3 | * 4 | * Copyright (c) 2009 by Peter Stokes 5 | * 6 | * This library is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | 23 | typedef enum { 24 | ARCAM_AV_ZONE1 = '1', 25 | ARCAM_AV_ZONE2 = '2' 26 | } arcam_av_zone_t; 27 | 28 | 29 | typedef enum { 30 | ARCAM_AV_POWER = '*', 31 | ARCAM_AV_VOLUME_CHANGE = '/', 32 | ARCAM_AV_VOLUME_SET = '0', 33 | ARCAM_AV_MUTE = '.', 34 | ARCAM_AV_SOURCE = '1', 35 | ARCAM_AV_SOURCE_TYPE = '7', 36 | ARCAM_AV_DIRECT = '3', 37 | ARCAM_AV_STEREO_DECODE = '4', 38 | ARCAM_AV_MULTI_DECODE = '5', 39 | ARCAM_AV_STEREO_EFFECT = '6' 40 | } arcam_av_cc_t; 41 | 42 | 43 | typedef enum { 44 | ARCAM_AV_OK = 'P', 45 | ARCAM_AV_ERROR = 'R' 46 | } arcam_av_rc_t; 47 | 48 | 49 | typedef enum { 50 | ARCAM_AV_POWER_STAND_BY = '0', 51 | ARCAM_AV_POWER_ON = '1', 52 | ARCAM_AV_POWER_REQUEST = '9' 53 | } arcam_av_power_t; 54 | 55 | 56 | typedef enum { 57 | ARCAM_AV_VOLUME_MIN = '0', 58 | ARCAM_AV_VOLUME_REQUEST = '9' 59 | } arcam_av_volume_t; 60 | 61 | 62 | typedef enum { 63 | ARCAM_AV_MUTE_ON = '0', 64 | ARCAM_AV_MUTE_OFF = '1', 65 | ARCAM_AV_MUTE_REQUEST = '9' 66 | } arcam_av_mute_t; 67 | 68 | 69 | typedef enum { 70 | ARCAM_AV_DIRECT_DISABLE = '0', 71 | ARCAM_AV_DIRECT_ENABLE = '1', 72 | ARCAM_AV_DIRECT_REQUEST = '9' 73 | } arcam_av_direct_t; 74 | 75 | 76 | typedef enum { 77 | ARCAM_AV_SOURCE_DVD = '0', 78 | ARCAM_AV_SOURCE_SAT = '1', 79 | ARCAM_AV_SOURCE_AV = '2', 80 | ARCAM_AV_SOURCE_PVR = '3', 81 | ARCAM_AV_SOURCE_VCR = '4', 82 | ARCAM_AV_SOURCE_CD = '5', 83 | ARCAM_AV_SOURCE_FM = '6', 84 | ARCAM_AV_SOURCE_AM = '7', 85 | ARCAM_AV_SOURCE_DVDA = '8', 86 | ARCAM_AV_SOURCE_REQUEST = '9' 87 | } arcam_av_source_t; 88 | 89 | 90 | typedef enum { 91 | ARCAM_AV_SOURCE_TYPE_ANALOGUE = '0', 92 | ARCAM_AV_SOURCE_TYPE_DIGITAL = '1', 93 | ARCAM_AV_SOURCE_TYPE_REQUEST = '9' 94 | } arcam_av_source_type_t; 95 | 96 | 97 | typedef enum { 98 | ARCAM_AV_STEREO_DECODE_MONO = '.', 99 | ARCAM_AV_STEREO_DECODE_STEREO = '/', 100 | ARCAM_AV_STEREO_DECODE_PLII_MOVIE = '0', 101 | ARCAM_AV_STEREO_DECODE_PLII_MUSIC = '1', 102 | ARCAM_AV_STEREO_DECODE_PLIIx_MOVIE = '3', 103 | ARCAM_AV_STEREO_DECODE_PLIIx_MUSIC = '4', 104 | ARCAM_AV_STEREO_DECODE_DOLBY_PL = '6', 105 | ARCAM_AV_STEREO_DECODE_NEO6_CINEMA = '7', 106 | ARCAM_AV_STEREO_DECODE_NEO6_MUSIC = '8', 107 | ARCAM_AV_STEREO_DECODE_REQUEST = '9' 108 | } arcam_av_stereo_decode_t; 109 | 110 | 111 | typedef enum { 112 | ARCAM_AV_MULTI_DECODE_MONO = '.', 113 | ARCAM_AV_MULTI_DECODE_STEREO = '/', 114 | ARCAM_AV_MULTI_DECODE_MULTI_CHANNEL = '0', 115 | ARCAM_AV_MULTI_DECODE_PLIIx = '2', 116 | ARCAM_AV_MULTI_DECODE_REQUEST = '9' 117 | } arcam_av_multi_decode_t; 118 | 119 | 120 | typedef enum { 121 | ARCAM_AV_STEREO_EFFECT_NONE = '0', 122 | ARCAM_AV_STEREO_EFFECT_MUSIC = '1', 123 | ARCAM_AV_STEREO_EFFECT_PARTY = '2', 124 | ARCAM_AV_STEREO_EFFECT_CLUB = '3', 125 | ARCAM_AV_STEREO_EFFECT_HALL = '4', 126 | ARCAM_AV_STEREO_EFFECT_SPORTS = '5', 127 | ARCAM_AV_STEREO_EFFECT_CHURCH = '6', 128 | ARCAM_AV_STEREO_EFFECT_REQUEST = '9' 129 | } arcam_av_stereo_effect_t; 130 | 131 | int arcam_av_connect(const char* port); 132 | int arcam_av_send(int fd, arcam_av_cc_t command, unsigned char param1, unsigned char param2); 133 | 134 | 135 | typedef struct arcam_av_state { 136 | union { 137 | struct { 138 | unsigned char power; 139 | unsigned char volume; 140 | unsigned char mute; 141 | unsigned char direct; 142 | unsigned char source; 143 | unsigned char source_type; 144 | unsigned char stereo_decode; 145 | unsigned char stereo_effect; 146 | unsigned char multi_decode; 147 | }; 148 | unsigned char state[9]; 149 | } zone1; 150 | union { 151 | struct { 152 | unsigned char power; 153 | unsigned char volume; 154 | unsigned char mute; 155 | unsigned char source; 156 | }; 157 | unsigned char state[4]; 158 | } zone2; 159 | } arcam_av_state_t; 160 | 161 | arcam_av_state_t* arcam_av_state_attach(const char* port); 162 | int arcam_av_state_detach(arcam_av_state_t* state); 163 | 164 | int arcam_av_server_start(pthread_t* thread, const char* port); 165 | int arcam_av_server_stop(pthread_t thread, const char* port); 166 | 167 | int arcam_av_client(const char* port); 168 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.59) 2 | AC_INIT(alsa-plugins, 1.2.12) 3 | AM_INIT_AUTOMAKE 4 | AC_PREFIX_DEFAULT(/usr) 5 | 6 | AM_MAINTAINER_MODE([enable]) 7 | 8 | AC_CONFIG_HEADERS(config.h) 9 | AC_CONFIG_MACRO_DIR([m4]) 10 | 11 | AC_PROG_CC 12 | AC_PROG_INSTALL 13 | AC_DISABLE_STATIC 14 | AM_PROG_LIBTOOL 15 | AC_HEADER_STDC 16 | 17 | CC_NOUNDEFINED 18 | 19 | PKG_CHECK_MODULES(ALSA, alsa >= 1.1.6) 20 | case $host_os in 21 | netbsd* | freebsd* | dragonfly* | openbsd*) 22 | AC_CHECK_LIB(asound, snd_pcm_ioplug_create,, 23 | AC_ERROR([*** libasound has no external plugin SDK])) 24 | ;; 25 | *) 26 | AC_CHECK_LIB(asound, snd_pcm_ioplug_create,, 27 | AC_ERROR([*** libasound has no external plugin SDK]), -ldl) 28 | ;; 29 | esac 30 | 31 | AC_ARG_ENABLE([oss], 32 | AS_HELP_STRING([--disable-oss], [Disable building of OSS plugin])) 33 | if test "x$enable_oss" != "xno"; then 34 | AM_CONDITIONAL(HAVE_OSS, true) 35 | AC_CHECK_HEADERS([sys/soundcard.h soundcard.h]) 36 | else 37 | AM_CONDITIONAL(HAVE_OSS, false) 38 | fi 39 | 40 | AC_ARG_ENABLE([mix], 41 | AS_HELP_STRING([--disable-mix], [Disable building of upmix and vdownmix plugins])) 42 | AS_IF([test "x$enable_mix" != "xno"], 43 | [AM_CONDITIONAL(HAVE_MIX, true)], 44 | [AM_CONDITIONAL(HAVE_MIX, false)]) 45 | 46 | AC_ARG_ENABLE([usbstream], 47 | AS_HELP_STRING([--disable-usbstream], [Disable building of usb_stream plugin])) 48 | AS_IF([test "x$enable_usbstream" != "xno"], 49 | [AM_CONDITIONAL(HAVE_USBSTREAM, true)], 50 | [AM_CONDITIONAL(HAVE_USBSTREAM, false)]) 51 | 52 | AC_ARG_ENABLE([arcamav], 53 | AS_HELP_STRING([--disable-arcamav], [Disable building of Arcam AV control plugin])) 54 | AS_IF([test "x$enable_arcamav" != "xno"], 55 | [AM_CONDITIONAL(HAVE_ARCAMAV, true)], 56 | [AM_CONDITIONAL(HAVE_ARCAMAV, false)]) 57 | 58 | AC_ARG_ENABLE([jack], 59 | AS_HELP_STRING([--disable-jack], [Disable building of JACK plugin])) 60 | 61 | if test "x$enable_jack" != "xno"; then 62 | PKG_CHECK_MODULES(JACK, jack >= 0.98, [HAVE_JACK=yes], [HAVE_JACK=no]) 63 | fi 64 | AM_CONDITIONAL(HAVE_JACK, test x$HAVE_JACK = xyes) 65 | 66 | AC_ARG_ENABLE([pulseaudio], 67 | AS_HELP_STRING([--disable-pulseaudio], [Disable building of pulseaudio plugin])) 68 | 69 | if test "x$enable_pulseaudio" != "xno"; then 70 | PKG_CHECK_MODULES(pulseaudio, [libpulse >= 0.9.11], [HAVE_PULSE=yes], [HAVE_PULSE=no]) 71 | fi 72 | AM_CONDITIONAL(HAVE_PULSE, test x$HAVE_PULSE = xyes) 73 | 74 | AC_ARG_ENABLE([samplerate], 75 | AS_HELP_STRING([--disable-samplerate], [Disable building of samplerate plugin])) 76 | 77 | if test "x$enable_samplerate" != "xno"; then 78 | PKG_CHECK_MODULES(samplerate, [samplerate], [HAVE_SAMPLERATE=yes], [HAVE_SAMPLERATE=no]) 79 | fi 80 | AM_CONDITIONAL(HAVE_SAMPLERATE, test x$HAVE_SAMPLERATE = xyes) 81 | 82 | AC_ARG_ENABLE([maemo-plugin], 83 | AS_HELP_STRING([--enable-maemo-plugin], 84 | [Build Maemo DSP plugin]), 85 | [HAVE_MAEMO_PLUGIN="$enableval"], [HAVE_MAEMO_PLUGIN="no"]) 86 | AM_CONDITIONAL(HAVE_MAEMO_PLUGIN, test x$HAVE_MAEMO_PLUGIN = xyes) 87 | 88 | AC_ARG_ENABLE([maemo-resource-manager], 89 | AS_HELP_STRING([--enable-maemo-resource-manager], 90 | [Use Maemo resource manager]), 91 | [use_maemo_rm="$enableval"], [use_maemo_rm="no"]) 92 | 93 | if test "$use_maemo_rm" = "yes"; then 94 | PKG_CHECK_MODULES(DBUS, [dbus-1], [HAVE_DBUS=yes], [HAVE_DBUS=no]) 95 | 96 | if test "$HAVE_DBUS" = "yes"; then 97 | AC_DEFINE(USE_RESOURCE_MANAGER, 1,"Use dbus server as a resouce manager") 98 | else 99 | AC_ERROR([You must have D-Bus installed if you want to enable the Maemo resource manager]) 100 | fi 101 | fi 102 | 103 | AC_ARG_ENABLE([libav], 104 | AS_HELP_STRING([--disable-libav], [Do not build plugins depending on libav/ffmpeg (a52,lavrate...)])) 105 | 106 | if test "x$enable_libav" != "xno"; then 107 | PKG_CHECK_MODULES(LIBAV, [libavcodec libavutil libswresample], [HAVE_LIBAV=yes], [HAVE_LIBAV=no]) 108 | fi 109 | 110 | if test "x$HAVE_LIBAV" = "xno"; then 111 | AC_ARG_WITH([libav-includedir], 112 | AS_HELP_STRING([--with-libav-includedir=dir], 113 | [Libav/ffmpeg include directory]), 114 | [LIBAV_CFLAGS="-I$(withval)"], [LIBAV_CFLAGS=""]) 115 | AC_ARG_WITH([libav-libdir], 116 | AS_HELP_STRING([--with-libav-libdir=dir], 117 | [Libav/ffmpeg library directory]), 118 | [LIBAV_LIBS="-L$withval"], [LIBAV_LIBS=""]) 119 | 120 | CFLAGS_saved="$CFLAGS" 121 | LDFLAGS_saved="$LDFLAGS" 122 | CFLAGS="$CFLAGS $LIBAV_CFLAGS" 123 | LDFLAGS="$LDFLAGS $LIBAV_LIBS" 124 | AC_CHECK_LIB([avcodec], [avcodec_open], [HAVE_LIBAV=yes], [HAVE_LIBAV=no]) 125 | CFLAGS="$CFLAGS_saved" 126 | LDFLAGS="$LDFLAGS_saved" 127 | LIBAV_CODEC_LIBS="-lavcodec" 128 | LIBAV_RESAMPLE_LIBS="-lavresample -lavutil" 129 | fi 130 | 131 | AM_CONDITIONAL(HAVE_LIBAV, test x$HAVE_LIBAV = xyes) 132 | AC_SUBST(LIBAV_CFLAGS) 133 | AC_SUBST(LIBAV_LIBS) 134 | AC_SUBST(LIBAV_CODEC_LIBS) 135 | AC_SUBST(LIBAV_RESAMPLE_LIBS) 136 | 137 | AC_ARG_ENABLE([a52], 138 | AS_HELP_STRING([--disable-a52], [Disable building of A52 encoder plugin])) 139 | 140 | if test "x$enable_a52" != "xno" -a "$HAVE_LIBAV" = "yes"; then 141 | HAVE_A52=yes 142 | fi 143 | AM_CONDITIONAL(HAVE_A52, test x$HAVE_A52 = xyes) 144 | 145 | AC_ARG_ENABLE([lavrate], 146 | AS_HELP_STRING([--disable-lavrate], [Disable building of libav/ffmpeg rate plugin])) 147 | 148 | if test "x$enable_lavrate" != "xno" -a "$HAVE_LIBAV" = "yes"; then 149 | HAVE_LAVRATE=yes 150 | fi 151 | AM_CONDITIONAL(HAVE_LAVRATE, test x$HAVE_LAVRATE = xyes) 152 | 153 | AC_ARG_ENABLE([speexdsp], 154 | AS_HELP_STRING([--disable-speexdsp], [Disable building of speexdsp plugin])) 155 | 156 | if test "x$enable_speexdsp" != "xno"; then 157 | PKG_CHECK_MODULES(speexdsp, [speexdsp >= 1.2rc2], [HAVE_SPEEXDSP="yes"], [HAVE_SPEEXDSP=""]) 158 | fi 159 | AM_CONDITIONAL(HAVE_SPEEXDSP, test "$HAVE_SPEEXDSP" = "yes") 160 | 161 | AC_ARG_WITH([speex], 162 | AS_HELP_STRING([--with-speex={builtin|lib|no}], 163 | [build speex resampler (built-in code, link with external lib, or no build)]), 164 | [PPH=$withval], [PPH="lib"]) 165 | 166 | USE_LIBSPEEX="" 167 | if test "$PPH" = "lib"; then 168 | if test "$HAVE_SPEEXDSP" = "yes"; then 169 | AC_CHECK_LIB([speexdsp], [speex_resampler_init], 170 | [USE_LIBSPEEX="yes"], [USE_LIBSPEEX=""]) 171 | fi 172 | if test "$USE_LIBSPEEX" = "yes"; then 173 | AC_DEFINE(USE_LIBSPEEX, 1, "Link with libspeex for resampler") 174 | else 175 | echo "No libspeex with resampler unit; use built-in code" 176 | PPH="builtin" 177 | fi 178 | fi 179 | 180 | AM_CONDITIONAL(HAVE_PPH, test "$PPH" = "builtin" -o "$PPH" = "lib") 181 | AM_CONDITIONAL(USE_LIBSPEEX, test "$PPH" = "lib") 182 | 183 | if test "$PPH" = "lib"; then 184 | AC_CHECK_HEADERS([speex/speexdsp_types.h]) 185 | fi 186 | 187 | test "x$prefix" = xNONE && prefix=$ac_default_prefix 188 | test "x$exec_prefix" = xNONE && exec_prefix=$prefix 189 | 190 | AC_ARG_ENABLE([aaf], 191 | AS_HELP_STRING([--disable-aaf], [Disable building of AAF plugin])) 192 | 193 | if test "x$enable_aaf" != "xno"; then 194 | PKG_CHECK_MODULES(AVTP, avtp >= 0.1, [HAVE_AAF=yes], [HAVE_AAF=no]) 195 | AC_CHECK_HEADERS([linux/if_ether.h linux/if_packet.h linux/net_tstamp.h], [], [HAVE_AAF=no]) 196 | fi 197 | AM_CONDITIONAL(HAVE_AAF, test x$HAVE_AAF = xyes) 198 | 199 | dnl ALSA plugin directory 200 | AC_ARG_WITH(plugindir, 201 | AS_HELP_STRING([--with-plugindir=dir], 202 | [path where ALSA plugin files are stored]), 203 | plugindir="$withval", plugindir="") 204 | if test -z "$plugindir"; then 205 | eval dir="$libdir" 206 | case "$dir" in 207 | /*) ;; 208 | *) dir="$dir" 209 | esac 210 | plugindir="$dir/alsa-lib" 211 | fi 212 | AC_DEFINE_UNQUOTED(ALSA_PLUGIN_DIR, "$plugindir", [directory containing ALSA add-on modules]) 213 | ALSA_PLUGIN_DIR="$plugindir" 214 | AC_SUBST(ALSA_PLUGIN_DIR) 215 | 216 | dnl ALSA data directory 217 | AC_ARG_WITH(alsadatadir, 218 | AS_HELP_STRING([--with-alsadatadir=dir], 219 | [path where ALSA data files are stored]), 220 | alsadatadir="$withval", alsadatadir="") 221 | if test -z "$alsadatadir"; then 222 | eval dir="$datadir" 223 | case "$dir" in 224 | /*) ;; 225 | *) eval dir="$dir" 226 | esac 227 | alsadatadir="$dir/alsa" 228 | fi 229 | AC_DEFINE_UNQUOTED(ALSA_DATA_DIR, "$alsadatadir", [directory containing ALSA data files]) 230 | ALSA_DATA_DIR="$alsadatadir" 231 | AC_SUBST(ALSA_DATA_DIR) 232 | 233 | dnl ALSA add-on global config directory 234 | AC_ARG_WITH(alsagconfdir, 235 | AS_HELP_STRING([--with-alsagconfdir=dir], 236 | [path where ALSA global add-on config files are stored]), 237 | alsagconfdir="$withval", alsagconfdir="") 238 | if test -z "$alsagconfdir"; then 239 | alsagconfdir="$ALSA_DATA_DIR/alsa.conf.d" 240 | fi 241 | AC_DEFINE_UNQUOTED(ALSA_GCONF_DIR, "$alsagconfdir", [directory containing global ALSA add-on config files]) 242 | ALSA_GCONF_DIR="$alsagconfdir" 243 | AC_SUBST(ALSA_GCONF_DIR) 244 | 245 | dnl ALSA add-on local config directory 246 | AC_ARG_WITH(alsalconfdir, 247 | AS_HELP_STRING([--with-alsalconfdir=dir], 248 | [path where ALSA local add-on config files are stored]), 249 | alsalconfdir="$withval", alsalconfdir="") 250 | if test -z "$alsalconfdir"; then 251 | eval dir="$sysconfdir" 252 | case "$dir" in 253 | /*) ;; 254 | *) dir="$dir" 255 | esac 256 | alsalconfdir="$dir/alsa/conf.d" 257 | fi 258 | AC_DEFINE_UNQUOTED(ALSA_LCONF_DIR, "$alsalconfdir", [directory containing local ALSA add-on config files]) 259 | ALSA_LCONF_DIR="$alsalconfdir" 260 | AC_SUBST(ALSA_LCONF_DIR) 261 | 262 | SAVE_PLUGINS_VERSION 263 | 264 | AC_OUTPUT([ 265 | Makefile 266 | oss/Makefile 267 | pph/Makefile 268 | jack/Makefile 269 | pulse/Makefile 270 | mix/Makefile 271 | rate/Makefile 272 | a52/Makefile 273 | rate-lav/Makefile 274 | maemo/Makefile 275 | doc/Makefile 276 | usb_stream/Makefile 277 | speex/Makefile 278 | arcam-av/Makefile 279 | aaf/Makefile 280 | ]) 281 | 282 | dnl Show the build conditions 283 | 284 | echo 285 | echo "Plugin directory: $ALSA_PLUGIN_DIR" 286 | echo "ALSA_CFLAGS: $ALSA_CFLAGS" 287 | echo "ALSA_LIBS: $ALSA_LIBS" 288 | echo "JACK plugin: $HAVE_JACK" 289 | if test "$HAVE_JACK" = "yes"; then 290 | echo " JACK_CFLAGS: $JACK_CFLAGS" 291 | echo " JACK_LIBS: $JACK_LIBS" 292 | fi 293 | echo "Pulseaudio plugin: $HAVE_PULSE" 294 | if test "$HAVE_PULSE" = "yes"; then 295 | echo " pulseaudio_CFLAGS: $pulseaudio_CFLAGS" 296 | echo " pulseaudio_LIBS: $pulseaudio_LIBS" 297 | fi 298 | echo "Samplerate plugin: $HAVE_SAMPLERATE" 299 | if test "$HAVE_SAMPLERATE" = "yes"; then 300 | echo " samplerate_CFLAGS: $samplerate_CFLAGS" 301 | echo " samplerate_LIBS: $samplerate_LIBS" 302 | fi 303 | echo "Maemo plugin: $HAVE_MAEMO_PLUGIN" 304 | echo " Using Osso resource manager: $use_maemo_rm" 305 | if test "$HAVE_LIBAV" = "yes"; then 306 | echo "Libav/ffmpeg config:" 307 | echo " LIBAV_CFLAGS: $LIBAV_CFLAGS" 308 | echo " LIBAV_LIBS: $LIBAV_LIBS / $LIBAV_CODEC_LIBS / $LIBAV_RESAMPLE_LIBS" 309 | fi 310 | echo "Libav A52 plugin: $HAVE_A52" 311 | echo "Libav rate plugin: $HAVE_LAVRATE" 312 | echo "Speex rate plugin: $PPH" 313 | echo "Speex preprocess plugin: $HAVE_SPEEXDSP" 314 | if test "$HAVE_SPEEX" = "yes"; then 315 | echo " speexdsp_CFLAGS: $speexdsp_CFLAGS" 316 | echo " speexdsp_LIBS: $speexdsp_LIBS" 317 | fi 318 | echo "AAF plugin: $HAVE_AAF" 319 | -------------------------------------------------------------------------------- /cvscompile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch ltconfig 4 | libtoolize --force --copy --automake 5 | aclocal $ACLOCAL_FLAGS 6 | autoheader 7 | automake --foreign --copy --add-missing 8 | touch depcomp # seems to be missing for old automake 9 | autoconf 10 | export CFLAGS='-O2 -Wall -W -pipe -g' 11 | echo "CFLAGS=$CFLAGS" 12 | echo "./configure $@" 13 | ./configure $@ || exit 1 14 | unset CFLAGS 15 | if [ -z "$CVSCOMPILE_NO_MAKE" ]; then 16 | make 17 | fi 18 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = 2 | 3 | EXTRA_DIST += README-pcm-oss 4 | EXTRA_DIST += upmix.txt vdownmix.txt 5 | EXTRA_DIST += README-jack 6 | EXTRA_DIST += README-pulse 7 | EXTRA_DIST += README-maemo 8 | EXTRA_DIST += samplerate.txt 9 | EXTRA_DIST += a52.txt 10 | EXTRA_DIST += aaf.txt 11 | EXTRA_DIST += lavrate.txt 12 | EXTRA_DIST += speexrate.txt 13 | EXTRA_DIST += speexdsp.txt 14 | EXTRA_DIST += README-arcam-av 15 | -------------------------------------------------------------------------------- /doc/README-arcam-av: -------------------------------------------------------------------------------- 1 | Arcam AV Amplifier ALSA Control plugin 2 | ====================================== 3 | 4 | This plugin exposes the controls for an Arcam AV amplifier 5 | (see: http://www.arcam.co.uk/) as an ALSA mixer device. 6 | 7 | To use this plugin you will need to connect the amplifier 8 | to the PC using an RS-232 null-modem cable and use the 9 | following ALSA configuration: 10 | 11 | ctl.arcam_av { 12 | type arcam_av 13 | port /dev/ttyS0 14 | } 15 | 16 | The "port" parameter is required and indicates the serial 17 | port to be used to communicate with the amplifier. There is 18 | an optional "zone" parameter, which accepts a value of 19 | either "1" (default) or "2", that indicates which of the 20 | amplifiers zones should be controlled. 21 | 22 | NB: You must ensure that any user accounts that are to use 23 | this plugin have both read and write access rights for the 24 | configured serial port. 25 | 26 | This plugin was developed and tested using an Arcam AVR 300 27 | amplifier. I believe most Arcam amplifiers use a sufficiently 28 | similar control system to be compatible with this plugin but 29 | your mileage may vary. 30 | -------------------------------------------------------------------------------- /doc/README-jack: -------------------------------------------------------------------------------- 1 | JACK <--> ALSA PCM plugin 2 | ========================= 3 | 4 | This plugin converts the ALSA API over JACK (Jack Audio Connection 5 | Kit, http://jackit.sf.net) API. ALSA native applications can work 6 | transparently together with jackd for both playback and capture. 7 | 8 | ALSA apps (playback) -> ALSA-lib -> JACK plugin -> JACK deamon 9 | ALSA apps (capture) <- ALSA-lib <- JACK plugin <- JACK daemon 10 | 11 | This plugin provides the PCM type "jack". The typical configuration 12 | looks like below: 13 | 14 | pcm.jack { 15 | type jack 16 | playback_ports { 17 | 0 alsa_pcm:playback_1 18 | 1 alsa_pcm:playback_2 19 | } 20 | capture_ports { 21 | 0 alsa_pcm:capture_1 22 | 1 alsa_pcm:pcapture_2 23 | } 24 | } 25 | 26 | Put the above to ~/.asoundrc (or /etc/asound.conf), and use "jack" PCM 27 | with your ALSA apps. For example, 28 | 29 | % aplay -Djack foo.wav 30 | 31 | The jack plugin can have two config options: playback_ports and 32 | capture_ports. Both are compound type config, including the following 33 | format: 34 | { 35 | channel port-name 36 | channel port-name 37 | ... 38 | } 39 | The first argument is the channel number (zero-based) and the second 40 | is the corresponding JACK port name. 41 | 42 | The plugin is installed in /usr/lib/alsa-lib directory as default, 43 | which is the default search path of additional plugins for alsa-lib. 44 | On a 64bit system like x86-64, the proper prefix option (typically, 45 | --prefix=/usr/lib64) must be given to configure script. 46 | 47 | -------------------------------------------------------------------------------- /doc/README-maemo: -------------------------------------------------------------------------------- 1 | The Debian Package osso-dsp-plugin-alsa 2 | ---------------------------- 3 | 4 | Comments regarding the Package 5 | 6 | Eduardo Valentin , Wed, 5 Apr 2006 10:28:06 +0300 7 | 8 | 9 | OSSO DSP SW <--> ALSA DSP plugin 10 | ======================== 11 | 12 | This plugin converts the ALSA API over PCM task nodes protocol. In this way, 13 | ALSA native applications can run over DSP Gateway and use DSP PCM task nodes. 14 | 15 | This plugin provides the PCM type "alsa_dsp". The typical configuration 16 | looks like below: 17 | 18 | # PCM 19 | pcm.!default { 20 | type alsa_dsp 21 | playback_device_file ["/dev/dsptask/pcm2"] 22 | recording_device_file ["/dev/dsptask/pcm_rec"] 23 | } 24 | 25 | Put the above to ~/.asoundrc (or /etc/asound.conf or /usr/share/alsa/alsa.conf), 26 | and use "default" PCM with your ALSA apps. For example: 27 | 28 | % aplay -Ddefault foo.wav 29 | % arecord -Ddefault foo.wav 30 | 31 | The alsa_dsp plugin can have two options for pcm interface: 32 | a. playback_device_file: this is a list of PCM task node device files whose 33 | alsa_dsp plugin is allowed to use to do playback. For example: /dev/dsptask/pcm2. 34 | b. recording_device_file: this is a list of PCM task node device files whose 35 | alsa_dsp plugin is allowed to use to do recording. For example: /dev/dsptask/pcm_rec. 36 | 37 | The alsa_dsp plugin will probe the dsp task node files you provide and 38 | will use the first one whose dsp PCM task is in UNINITIALISED state. 39 | If no dsp PCM task node is usable, alsa_dsp plugin will return an ENODEV 40 | error code. 41 | 42 | For the control interface, this plugin provides the CTL type "dsp_ctl". A 43 | typical configuration is: 44 | # Mixer 45 | ctl.!default { 46 | type dsp_ctl 47 | playback_devices ["/dev/dsptask/pcm2"] 48 | recording_devices ["/dev/dsptask/pcm_rec"] 49 | } 50 | 51 | Put the above to ~/.asoundrc (or /etc/asound.conf or /usr/share/alsa/alsa.conf), 52 | and use "default" CTL with your ALSA apps. For example: 53 | % alsamixer -Ddefault 54 | 55 | The dsp_ctl plugin can have two options for ctl interface: 56 | a. playback_devices: this is a list of PCM task node device files whose 57 | dsp_ctl plugin is allowed to use to do volume control changing. These 58 | devices will be handled under the "PCM Playback Volume" and "PCM Playback Switch" 59 | control names. 60 | b. recording_devices: this is a list of PCM task node device files whose 61 | dsp_ctl plugin is allowed to use to do volume control changing. 62 | These devices will be handled under the "Capture Switch" control name. 63 | 64 | # Supported formats: 65 | 66 | Playback: 67 | 16-bit PCM formats: 68 | S16_LE 69 | S16_BE 70 | U16_LE 71 | U16_BE 72 | 8-bit PCM formats: 73 | A_LAW 74 | MU_LAW 75 | U8 76 | S8 77 | Rates: 78 | 8 KHz, 11.025 KHz, 12 KHz, 16 KHz, 79 | 22.050 KHz, 24 KHz, 32 KHz, 44.1 KHz, 48 KHz 80 | Channels: Mono and Stereo 81 | Recording: 82 | 16-bit PCM formats: 83 | S16_LE 84 | 8-bit PCM formats: 85 | A_LAW 86 | MU_LAW 87 | Rates: 88 | 8 KHz 89 | Channels: Mono 90 | 91 | # Compilation 92 | To cross-compile the plugin inside scratchbox environment, you will 93 | need a libasound2 version of binaries and header files installed. 94 | Pthreads is also required. The source directory provides a Makefile. 95 | If you just type: 96 | 97 | % make clean 98 | % make 99 | 100 | under the source tree, it will generate the binaries under the 101 | "bin" sub-directory. Like: 102 | 103 | libasound_module_ctl_dsp_ctl.so and libasound_module_pcm_alsa_dsp.so 104 | 105 | The libasound_module_ctl_dsp_ctl.so is currently a symbolic link to 106 | libasound_module_pcm_alsa_dsp.so. 107 | 108 | You can just copy then to your /usr/lib/alsa-lib/ directory inside your 109 | target file system. 110 | 111 | You can also modify the behaviour of this plugin using macro definitions 112 | while compiling it. Here are macros whose can be used in CFLAGS (-D ): 113 | ERROR_DEBUG It enables error debug output. You have to 114 | change in "debug.h" file. Default is to debug. 115 | DEBUG It enables debug output. You have to change in 116 | "debug.h" file. Default is not to debug. 117 | NORMAL_DSP_TASK It enables utilization of extended fields in 118 | audio_status_info_t data structure (mute, 119 | samples_played_high, samples_played_low). 120 | You can change it in "Makefile". Default 121 | is NORMAL_DSP_TASK enabled. 122 | USE_RESOURCE_MANAGER If set, the resource manager D-BUS interface 123 | will be used for power management instead of 124 | the sysfs file. 125 | ERROR_ON_PM_FAILURE It controls this plugin behaviour if it fails 126 | while openning MIC power management file 127 | (/sys/devices/platform/audio-i2c/mic_enable) 128 | or calling the resource manager request() 129 | method (if USE_RESOURCE_MANAGER is set). 130 | If you enable this macro, this plugin will 131 | return an error code. Otherwise, it will 132 | just print a debug message, and will return 133 | sucess. You can change it in Makefile. Default 134 | is ERROR_ON_PM_FAILURE disabled. 135 | 136 | # Installation 137 | The plugin is installed in /usr/lib/alsa-lib directory as default, 138 | which is the default search path of additional plugins for alsa-lib. 139 | 140 | This plugin is expected to be compatible with any standard ALSA application. 141 | The only requirement is you have to compile it against the same libasound2 you 142 | have installed in your target system. You have to enable the external plugins 143 | support in libasound2: 144 | 145 | % cd $LIB_ASOUND2_SRC 146 | % ./configure --with-pcm-plugins=extplug 147 | 148 | You can get the latest version of libasound2 in http://www.alsa-project.org. 149 | There you can find more instructions of how to compile libasound2. The cross-compilation 150 | for ARM architecture is straightforward inside the scratchbox environment. 151 | 152 | 153 | # Applications 154 | 155 | Alsa-utils: 156 | Also from http://www.alsa-project.org, you can find alsa-utils package sources. 157 | This package constains standard ALSA application, like amixer, alsamixer and 158 | aplay/arecord. 159 | 160 | The compilation of alsa-utils is also straightforward inside scratchbox environment. 161 | The only requirement is you will need to have libasound2 (and libncurses) installed 162 | inside your scratchbox environment to be able to compile alsa-utils. 163 | 164 | After compiling and installing applications on your target, you can 165 | use them with this plugin specifing the correct pcm device. For example, 166 | if you have installed alsaplayer on your target, you can specify an alsa pcm 167 | device with: 168 | target # alsaplayer -d default 169 | 170 | #Limitation 171 | 172 | - While the plugin is using a pcm task node, another applications, 173 | for example gstreamer, can not use the same task node. This will cause 174 | unexpected behaviour. 175 | - If an application does not close alsa device properly, this plugin 176 | will not have chance to release all reserved resouces. One expected 177 | behaviour in this case is to have -EBUSY error for following applications 178 | whose try to open the same alsa device. Partialy solved (version 0.6) 179 | with __attribute__((destructor)) functions. But if the application 180 | receives an uncaught signal, resources may be kept unreleased. 181 | - If many requests to volume information read / write is done in the 182 | same alsa device while it is being used to do playback, this playback 183 | could be affected and some little stops can be heard. 184 | -------------------------------------------------------------------------------- /doc/README-pcm-oss: -------------------------------------------------------------------------------- 1 | OSS <--> ALSA PCM plugin 2 | ======================== 3 | 4 | This plugin converts the ALSA API over OSS API. With this plugin, 5 | ALSA native apps can run on OSS drivers. 6 | 7 | This plugin provides the PCM type "oss". The typical configuration 8 | looks like below: 9 | 10 | pcm.oss { 11 | type oss 12 | device /dev/dsp 13 | } 14 | 15 | Put the above to ~/.asoundrc (or /etc/asound.conf), and use "oss" PCM 16 | with your ALSA apps. For example, 17 | 18 | % aplay -Doss foo.wav 19 | 20 | For playing arbitrary formats, you should use "plug" layer together, 21 | 22 | % aplay -Dplug:oss foo.wav 23 | 24 | The oss plugin can have an option: device. This specifies the device 25 | file path of OSS to open. If not given, /dev/dsp is used. 26 | 27 | The function supported by this plugin is limited. For example, you 28 | cannot use dmix together with this plugin. Don't expect too much :) 29 | 30 | The plugin is installed in /usr/lib/alsa-lib directory as default, 31 | which is the default search path of additional plugins for alsa-lib. 32 | On a 64bit system like x86-64, the proper prefix option (typically, 33 | --prefix=/usr/lib64) must be given to configure script. 34 | -------------------------------------------------------------------------------- /doc/README-pulse: -------------------------------------------------------------------------------- 1 | PulseAudio <--> ALSA plugins 2 | ============================ 3 | 4 | This plugin allows any program that uses the ALSA API to access a PulseAudio 5 | sound daemon. In other words, native ALSA applications can play and record 6 | sound across a network. 7 | 8 | There are two plugins in the suite, one for PCM and one for mixer control. A 9 | typical configuration will look like: 10 | 11 | pcm.pulse { 12 | type pulse 13 | } 14 | 15 | ctl.pulse { 16 | type pulse 17 | } 18 | 19 | Put the above in ~/.asoundrc, or /etc/asound.conf, and use "pulse" as device 20 | in your ALSA applications. For example: 21 | 22 | % aplay -Dpulse foo.wav 23 | % amixer -Dpulse 24 | 25 | PulseAudio will accept more or less any format you throw at it. So a plug 26 | wrapper is unnecessary. Mixing is also handled so dmix will only cause a 27 | performance hit without any gain. 28 | 29 | The plugins will respect your PulseAudio environment variables (like 30 | PULSE_SERVER), but you can override these in ALSA's configuration files. 31 | 32 | Both plugins accept the "server" parameter, specifying which PulseAudio server 33 | to contact. Both also accept the "device" parameter, which indicate which 34 | source and sink to use. 35 | 36 | The mixer control plugin also accepts the parameters "source" and "sink" for 37 | when you need to specify a sink/source combination with different names. If 38 | you need to do this with PCM:s then specify two PCM:s with different "device". 39 | 40 | If you do not specify any source and/or sink, then the server's defaults will 41 | be used. 42 | 43 | When "fallback" option is set, the plugin will try to open the given PCM 44 | (or control) automatically when connecting to PA server fails. Typically, 45 | it should point to "sysdefault", which was introduced recently in alsa-lib, 46 | so that the system-default setup is used even when you overwrite "default" 47 | PCM and control definitions. 48 | 49 | pcm.pulse { 50 | type pulse 51 | fallback "sysdefault" 52 | } 53 | 54 | ctl.pulse { 55 | type pulse 56 | fallback "sysdefault" 57 | } 58 | 59 | pcm.!default "pulse" 60 | ctl.!default "pulse" 61 | -------------------------------------------------------------------------------- /doc/a52.txt: -------------------------------------------------------------------------------- 1 | A52 OUTPUT PLUGIN 2 | ================= 3 | 4 | This plugin converts S16(P), S32P, or FLTP formats to an A52 compressed 5 | stream and sends it to an S/PDIF output. It requires libavcodec for 6 | encoding the audio stream. 7 | 8 | The input format is determined by the version of libavcodec it is 9 | compiled against and which ac3 codec libavcodec is configured to use. 10 | 11 | A global configuration, /usr/share/alsa/alsa.conf.d/60-a52-encoder.conf 12 | defines a52 PCMs for devices with the IEC958 non-audio status bit set. 13 | 14 | A PCM using this plugin can be manually defined like below: 15 | 16 | pcm.myout { 17 | type a52 18 | } 19 | 20 | In addition, the following options are available: 21 | 22 | - The "card" option specifies the card ID or number of the SPDIF. 23 | The output PCM becomes "iec958:{CARD=$CARD}" with extra AESx 24 | settings. When omitted, the default card is used. 25 | 26 | - The "slavepcm" option specifies a string of the slave PCM 27 | explicitly. This is useful if a device has no proper SPDIF 28 | configuration (e.g. usb-audio), or if you want to pass your own PCM 29 | definition. This option is exclusive with "card" option. 30 | 31 | - The "rate" option specifies the input/output sample rate in HZ. 32 | The accepted rate is either 44100 or 48000. 33 | When omitted, 48000 is used. 34 | 35 | - The "channels" option specifies the number of _input_ channels. 36 | It must be either 2, 4 or 6. The default value is 6. 37 | 38 | - The "bitrate" option specifies the bit-rate of the compressed 39 | stream in kbps. Too small or too big value may not be accepted by 40 | the encoder. When omitted, 448 is used. 41 | 42 | - The "format" option specifies the output format type. It's either 43 | S16_LE or S16_BE. As default, S16_LE is used. 44 | 45 | An example using the secondary card, 44.1kHz, 4 channels, output 46 | bitrate 256kbps and output format S16_BE looks like below: 47 | 48 | pcm.myout { 49 | type a52 50 | card 1 51 | rate 44100 52 | channels 4 53 | bitrate 256 54 | format S16_BE 55 | } 56 | 57 | For using slavepcm option, 58 | 59 | pcm.mypcm { 60 | card 1 61 | device 2 62 | } 63 | 64 | pcm.myout { 65 | type a52 66 | slavepcm "mypcm" 67 | } 68 | 69 | 70 | The plugin only reads the format determined by libavcodec (native- 71 | endian S16(P), S32P or FLTP) as input, so you'll need a plug layer to 72 | appropriately convert it. 73 | -------------------------------------------------------------------------------- /doc/aaf.txt: -------------------------------------------------------------------------------- 1 | AVTP Audio Format (AAF) Plugin 2 | ============================== 3 | 4 | Overview 5 | -------- 6 | 7 | The AAF plugin is a PCM plugin that uses Audio Video Transport Protocol (AVTP) 8 | to transmit/receive audio samples through a Time-Sensitive Network (TSN) 9 | capable network. The plugin enables media applications to easily implement AVTP 10 | Talker and Listener functionalities. 11 | 12 | AVTP is designed to take advantage of generalized Precision Time Protocol 13 | (gPTP) and Forwarding and Queuing Enhancements for Time-Sensitive Streams 14 | (FQTSS). gPTP ensures AVTP talkers and listeners share the same time reference 15 | so the presentation time from AVTP can be used to inform when PCM samples 16 | should be presented to the application layer. FQTSS provides bandwidth 17 | reservation and traffic prioritization for the AVTP stream. 18 | 19 | gPTP functionality is provided by the Linuxptp project while FQTSS 20 | functionality is provided by Linux Traffic Control system since kernel version 21 | 4.15. 22 | 23 | gPTP Setup 24 | ---------- 25 | 26 | The Linuxptp project provides the ptp4l daemon, which synchronizes the PTP 27 | clock from NIC, and the pmc tool which communicates with ptp4l to get/set 28 | some runtime settings. The project also provides the phc2sys daemon which 29 | synchronizes the PTP clock and system clock. 30 | 31 | The AAF Plugin requires system clock is synchronized with PTP clock and TAI 32 | offset is properly set in the kernel. ptp4l and phc2sys can be set up in many 33 | different ways, below we provide an example that fullfils the plugin 34 | requirements. For further information check ptp4l(8) and phc2sys(8). 35 | 36 | In the following instructions, replace $IFNAME by your PTP capable NIC 37 | interface. The gPTP.cfg file mentioned below can be found in /usr/share/ 38 | doc/linuxptp/ (depending on your distro). 39 | 40 | Synchronize PTP clock with PTP time: 41 | 42 | $ ptp4l -f gPTP.cfg -i $IFNAME 43 | 44 | Enable TAI offset to be automatically set by phc2sys: 45 | 46 | $ pmc -u -t 1 -b 0 'SET GRANDMASTER_SETTINGS_NP \ 47 | clockClass 248 clockAccuracy 0xfe \ 48 | offsetScaledLogVariance 0xffff \ 49 | currentUtcOffset 37 leap61 0 leap59 0 \ 50 | currentUtcOffsetValid 1 pTimescale 1 \ 51 | timeTraceable 1 frequencyTraceable 0 timeSource 0xa0' 52 | 53 | Synchronize system clock with PTP clock: 54 | 55 | $ phc2sys -f gPTP.cfg -s $IFNAME -c CLOCK_REALTIME -w 56 | 57 | The commands above should be run on both AVTP Talker and Listener hosts. 58 | 59 | Traffic Control Setup 60 | --------------------- 61 | 62 | The Linux Traffic Control system provides the mqprio and cbs qdiscs which 63 | enable FQTSS on Linux. Below we provide an example to configure those qdiscs in 64 | order to transmit an AAF stream with the following features: class A, 6 audio 65 | frames per AVTPDU, 48 kHz sampling rate, 16-bit sample size, stereo. For 66 | further information on how to configure these qdiscs check tc-mqprio(8) and 67 | tc-cbs(8) man pages. 68 | 69 | On the host that will run as AVTP Talker (i.e. plugin in playback mode), run 70 | the following commands: 71 | 72 | Configure mpqrio qdisc (replace $MQPRIO_HANDLE_ID by an unused handle ID): 73 | 74 | $ tc qdisc add dev $IFNAME parent root handle $MQPRIO_HANDLE_ID \ 75 | mqprio num_tc 3 map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \ 76 | queues 1@0 1@1 2@2 hw 0 77 | 78 | Configure cbs qdisc (replace $CBS_HANDLE_ID by an unused handle ID): 79 | 80 | $ tc qdisc replace dev $IFNAME parent $MQPRIO_HANDLE_ID:1 \ 81 | handle $CBS_HANDLE_ID cbs idleslope 5760 \ 82 | sendslope -994240 hicredit 9 locredit -89 offload 1 83 | 84 | The plugin implements a transmission mechanism that relies on ETF qdisc so make 85 | sure it is properly configured in the system. It could be configured many way, 86 | below follows an example. 87 | 88 | $ tc qdisc add dev $IFNAME parent $CBS_HANDLE_ID:1 etf \ 89 | clockid CLOCK_TAI delta 500000 offload 90 | 91 | No Traffic Control configuration is required at the host running as AVTP 92 | Listener. 93 | 94 | Plugin Dependencies 95 | ------------------- 96 | 97 | The AAF plugin uses libavtp to handle AVTP packetization. Libavtp source code 98 | can be found in https://github.com/AVnu/libavtp as well as instructions to 99 | build and install it. 100 | 101 | The plugin also depends on some kernel API headers such as linux/if_ether.h so 102 | make sure you have them installed in your system. 103 | 104 | If libavtp or the kernel headers aren't detected by configure, the plugin isn't 105 | built. 106 | 107 | Plugin Configuration 108 | -------------------- 109 | 110 | The plugin parameters are passed via ALSA configuration file. They are defined 111 | as follows: 112 | 113 | * ifname: Network interface used to transmit/receive AVTP packets. 114 | 115 | * addr: Stream destination MAC address. 116 | 117 | * prio: Priority used by the plugin to transmit AVTP traffic. This 118 | option is relevant only when operating in playback mode. 119 | 120 | * streamid: Stream ID associated with the AAF stream transmitted or 121 | received by the plugin. 122 | 123 | * mtt: Maximum Transit Time (in microseconds) as defined in AVTP spec 124 | section 4.3.3. This option is relevant only when operating in 125 | playback mode. 126 | 127 | * time_uncertainty: Maximum Time Uncertainty (in microseconds) as 128 | defined by AVTP spec section 4.3.3. This option is relevant only when 129 | operating in playback mode. 130 | 131 | * frames_per_pdu: Number of audio frames transmitted in one AVTPDU. 132 | 133 | * ptime_tolerance: Presentation time tolerance in microseconds. 134 | AVTPDUs with presentation time off by +- ptime_tolerance are not 135 | considered invalid. This option is relevant only when operating in 136 | capture mode. 137 | 138 | Plugin Usage 139 | ------------ 140 | 141 | The plugin provides the PCM type "aaf". Configure an AAF PCM virtual device 142 | according to the AAF stream you want to transmit or receive. A hypothetical 143 | configuration for the stream described in the 'FQTSS Setup' section is shown 144 | below: 145 | 146 | pcm.aaf0 { 147 | type aaf 148 | ifname eth0 149 | addr 01:AA:AA:AA:AA:AA 150 | prio 3 151 | streamid AA:BB:CC:DD:EE:FF:0000 152 | mtt 2000 153 | time_uncertainty 125 154 | frames_per_pdu 6 155 | ptime_tolerance 100 156 | } 157 | 158 | Put the above to ~/.asoundrc (or /etc/asound.conf), and use the AAF PCM virtual 159 | device 'aaf0' with your favorite alsa-utils tool. Note that the plugin requires 160 | the period size is multiple of the 'frames_per_pdu' configuration. 161 | 162 | For example, to stream the pink noise generated by 'speaker-test', run: 163 | 164 | $ speaker-test -F S16_BE -c 2 -r 48000 -D aaf0 -p 12500 165 | 166 | To receive the AAF stream generated by the command above, run the following 167 | command in another host: 168 | 169 | $ arecord -t raw -f S16_BE -c 2 -r 48000 -D aaf0 -vv /dev/null -F 12500 170 | 171 | If you want to playback the contents of the AAF stream, change the command-line 172 | above so the output from 'arecord' is redirected to 'aplay', or simply use the 173 | 'alsaloop' tool. 174 | -------------------------------------------------------------------------------- /doc/lavrate.txt: -------------------------------------------------------------------------------- 1 | Rate Converter Plugin Using libavresample 2 | =========================================0 3 | 4 | The plugin in rate-lavr subdirectory is an external rate converter using 5 | libswresample library. You can use this rate converter plugin by defining a 6 | rate PCM with "converter" parameter, such as: 7 | 8 | pcm.my_rate { 9 | type rate 10 | slave.pcm "hw" 11 | converter "lavrate" 12 | } 13 | 14 | The plug plugin has also a similar field, "rate_converter". 15 | 16 | Or, more easily, define a global variable "defaults.pcm.rate_converter", 17 | which is used as the default converter type by plug and rate plugins: 18 | 19 | defaults.pcm.rate_converter "lavrate" 20 | 21 | Write the above in your ~/.asoundrc or /etc/asound.conf. 22 | 23 | The following converter types are available: 24 | 25 | - lavcrate_higher Use length=64 26 | - lavcrate_high Use length=32 27 | - lavcrate Use length=16 28 | - lavcrate_fast Use length=8 29 | - lavcrate_faster Use length=4 30 | 31 | Linear interpolation and cutoff values are automatically used depending on 32 | the supplied parameters and whether the plugin is used to upsample or 33 | downsample. 34 | -------------------------------------------------------------------------------- /doc/samplerate.txt: -------------------------------------------------------------------------------- 1 | Rate Converter Plugin Using Libsamplerate 2 | ========================================= 3 | 4 | The plugin in rate subdirectory is an external rate converter using 5 | libsamplerate by Erik de Castro Lopo. You can use this rate converter 6 | plugin by defining a rate PCM with "converter" parameter, such as: 7 | 8 | pcm.my_rate { 9 | type rate 10 | slave.pcm "hw" 11 | converter "samplerate" 12 | } 13 | 14 | The plug plugin has also a similar field, "rate_converter". 15 | 16 | Or, more easily, define a global variable "defaults.pcm.rate_converter", 17 | which is used as the default converter type by plug and rate plugins: 18 | 19 | defaults.pcm.rate_converter "samplerate" 20 | 21 | Write the above in your ~/.asoundrc or /etc/asound.conf. 22 | 23 | The following converter types are available: 24 | 25 | - samplerate_best Use SRC_SINC_BEST_QUALITY 26 | - samplerate_medium Use SRC_SINC_MEDIUM_QUALITY 27 | - samplerate Use SRC_SINC_FASTEST 28 | - samplerate_order Use SRC_ZERO_ORDER_HOLD 29 | - samplerate_linear Use SRC_LINEAR 30 | 31 | -------------------------------------------------------------------------------- /doc/speexdsp.txt: -------------------------------------------------------------------------------- 1 | Speex Preprocessing Plugin 2 | ========================== 3 | 4 | This plugin provides a pre-processing of a mono stream like denoise 5 | using libspeex DSP API. You can use the plugin with the plugin type 6 | "speex" like below: 7 | 8 | pcm.my_pcm { 9 | type speex 10 | slave.pcm "default" 11 | } 12 | 13 | Then record like 14 | 15 | % arecord -fdat -c1 -Dplug:my_pcm foo.wav 16 | 17 | so that you'll get 48kHz mono stream with the denoising effect. 18 | 19 | Right now, the plugin supports only a mono stream. 20 | The accepted format is only S16. 21 | 22 | The following parameters can be set optionally: 23 | 24 | * frames 25 | 26 | This controls the frames of the intermediate buffer. This 27 | corresponds to the latency of the filter. As default it's 64. 28 | 29 | * denoise 30 | 31 | A boolean value to enable/disable the denoise function. Default is 32 | yes. 33 | 34 | * agc 35 | 36 | A boolean value to enable/disable the auto-gain control function. 37 | Default is no. 38 | 39 | * agc_level 40 | 41 | A float value for the automatic gain-control level. Default is 8000. 42 | 43 | * dereverb 44 | 45 | A boolean value to enable/disable dereverb function. Default is no. 46 | 47 | * echo 48 | 49 | A boolean value to enable/disable echo-cancellation function. 50 | Default is no. 51 | 52 | * filter_length 53 | 54 | Number of samples of echo to cancel. As default it's 256. 55 | 56 | For example, you can enable agc like 57 | 58 | pcm.my_pcm { 59 | type speex 60 | slave.pcm "default" 61 | agc 1 62 | agc_level 8000 63 | } 64 | -------------------------------------------------------------------------------- /doc/speexrate.txt: -------------------------------------------------------------------------------- 1 | Rate Converter Plugin Using Speex Resampler 2 | =========================================== 3 | 4 | The plugin in rate subdirectory is an external rate converter using 5 | the Speex resampler (aka Public Parrot Hack) by Jean-Marc Valin. You can 6 | use this rate converter plugin by defining a rate PCM with "converter" 7 | parameter, such as: 8 | 9 | pcm.my_rate { 10 | type rate 11 | slave.pcm "hw" 12 | converter "speexrate" 13 | } 14 | 15 | The plug plugin has also a similar field, "rate_converter". 16 | 17 | Or, more easily, define a global variable "defaults.pcm.rate_converter", 18 | which is used as the default converter type by plug and rate plugins: 19 | 20 | defaults.pcm.rate_converter "speexrate" 21 | 22 | Write the above in your ~/.asoundrc or /etc/asound.conf. 23 | 24 | The following converter types are available: 25 | 26 | - speexrate_best Use quality 10 (equivalent to SRC_SINC_BEST_QUALITY) 27 | - speexrate_medium Use quality 5 (equivalent to SRC_SINC_MEDIUM_QUALITY) 28 | - speexrate Use quality 3 (equivalent to SRC_SINC_FASTEST) 29 | 30 | -------------------------------------------------------------------------------- /doc/upmix.txt: -------------------------------------------------------------------------------- 1 | UPMIX PLUGIN 2 | ============ 3 | 4 | The upmix plugin is an easy-to-use plugin for upmixing to 4 or 5 | 6-channel stream. The number of channels to be expanded is determined 6 | by the slave PCM or explicitly via channel option. For example, the 7 | following PCM defines upmixing to 5.1 from 1-6 channels input: 8 | 9 | pcm.upmix51 { 10 | type upmix 11 | slave.pcm "surround51" 12 | } 13 | 14 | You can use this PCM as a default one by defining below: 15 | 16 | pcm.!default "plug:upmix51" 17 | 18 | The upmix plugin copies left and right channels to rear left and right 19 | with a certain delay. The delay size can be specified by "delay" PCM 20 | option in msec. For example, to set 10ms delay in the above case: 21 | 22 | pcm.upmix51 { 23 | type upmix 24 | slave.pcm "surround51" 25 | delay 10 26 | } 27 | 28 | As default, 15ms delay is used. 29 | 30 | The channel option specifies the number of channels of output. Either 31 | 4 or 6 channels are supported. When 0 is passed, the plugin tries 4 32 | or 6 channels appropriately suitable for the slave pcm. The channel 33 | option is useful if the slave PCM has no strict input condition (like 34 | plug or route plugin). 35 | 36 | pcm.myupmix { 37 | type upmix 38 | slave.pcm "something" 39 | channels 6 40 | } 41 | 42 | The center and LFE channels are the average of sum of left and right 43 | signals. 44 | 45 | The accepted format is currently only S16. 46 | -------------------------------------------------------------------------------- /doc/vdownmix.txt: -------------------------------------------------------------------------------- 1 | VDOWNMIX PLUGIN 2 | =============== 3 | 4 | The vdownmix plugin is a downmixer from 4-6 channels to 2-channel 5 | stereo headphone output. This plugin processes the input signals with 6 | a simple spacialization, so the output sounds like a kind of "virtual 7 | surround". 8 | 9 | For example, define the below: 10 | 11 | pcm.!surround51 { 12 | type vdownmix 13 | slave.pcm "default" 14 | } 15 | pcm.!surround40 { 16 | type vdownmix 17 | slave.pcm "default" 18 | } 19 | 20 | and the outputs from video player to these PCMs are converted to the 21 | default 2.0 output with a proper downmix. 22 | 23 | The accepted format is currently only S16. 24 | -------------------------------------------------------------------------------- /gitcompile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch ltconfig 4 | libtoolize --force --copy --automake 5 | aclocal $ACLOCAL_FLAGS 6 | autoheader 7 | automake --foreign --copy --add-missing 8 | touch depcomp # seems to be missing for old automake 9 | autoconf 10 | export CFLAGS='-O2 -Wall -W -pipe -g' 11 | echo "CFLAGS=$CFLAGS" 12 | echo "./configure $@" 13 | ./configure $@ || exit 1 14 | unset CFLAGS 15 | if [ -z "$GITCOMPILE_NO_MAKE" ]; then 16 | make 17 | fi 18 | -------------------------------------------------------------------------------- /install-hooks.am: -------------------------------------------------------------------------------- 1 | install-conf-hook: 2 | mkdir -p $(DESTDIR)$(ALSA_LCONF_DIR) 3 | @(echo cd $(DESTDIR)$(ALSA_LCONF_DIR); \ 4 | cd $(DESTDIR)$(ALSA_LCONF_DIR); \ 5 | for i in $(GCONF_FILES); do \ 6 | echo $(RM) $$i";" ln -s $(ALSA_GCONF_DIR)/$$i .; \ 7 | $(RM) $$i; \ 8 | ln -s $(ALSA_GCONF_DIR)/$$i .; \ 9 | done) 10 | uninstall-conf-hook: 11 | @(echo cd $(DESTDIR)$(ALSA_LCONF_DIR); \ 12 | cd $(DESTDIR)$(ALSA_LCONF_DIR); \ 13 | for i in $(GCONF_FILES); do \ 14 | echo $(RM) $$i; \ 15 | $(RM) $$i; \ 16 | done) 17 | -------------------------------------------------------------------------------- /jack/50-jack.conf: -------------------------------------------------------------------------------- 1 | pcm.jack { 2 | type jack 3 | playback_ports { 4 | 0 system:playback_1 5 | 1 system:playback_2 6 | } 7 | capture_ports { 8 | 0 system:capture_1 9 | 1 system:capture_2 10 | } 11 | hint { 12 | show { 13 | @func refer 14 | name defaults.namehint.basic 15 | } 16 | description "JACK Audio Connection Kit" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jack/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 50-jack.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_jack_LTLIBRARIES = libasound_module_pcm_jack.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_pcm_jackdir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @JACK_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_pcm_jack_la_SOURCES = pcm_jack.c 15 | libasound_module_pcm_jack_la_LIBADD = @ALSA_LIBS@ @JACK_LIBS@ -lpthread 16 | 17 | include ../install-hooks.am 18 | 19 | install-data-hook: install-conf-hook 20 | 21 | uninstall-local: uninstall-conf-hook 22 | -------------------------------------------------------------------------------- /m4/attributes.m4: -------------------------------------------------------------------------------- 1 | dnl Macros to check the presence of generic (non-typed) symbols. 2 | dnl Copyright (c) 2006-2008 Diego Pettenò 3 | dnl Copyright (c) 2006-2008 xine project 4 | dnl 5 | dnl This program is free software; you can redistribute it and/or modify 6 | dnl it under the terms of the GNU General Public License as published by 7 | dnl the Free Software Foundation; either version 2, or (at your option) 8 | dnl any later version. 9 | dnl 10 | dnl This program is distributed in the hope that it will be useful, 11 | dnl but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | dnl GNU General Public License for more details. 14 | dnl 15 | dnl You should have received a copy of the GNU General Public License 16 | dnl along with this program; if not, write to the Free Software 17 | dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | dnl 02110-1301, USA. 19 | dnl 20 | dnl As a special exception, the copyright owners of the 21 | dnl macro gives unlimited permission to copy, distribute and modify the 22 | dnl configure scripts that are the output of Autoconf when processing the 23 | dnl Macro. You need not follow the terms of the GNU General Public 24 | dnl License when using or distributing such scripts, even though portions 25 | dnl of the text of the Macro appear in them. The GNU General Public 26 | dnl License (GPL) does govern all other use of the material that 27 | dnl constitutes the Autoconf Macro. 28 | dnl 29 | dnl This special exception to the GPL applies to versions of the 30 | dnl Autoconf Macro released by this project. When you make and 31 | dnl distribute a modified version of the Autoconf Macro, you may extend 32 | dnl this special exception to the GPL to apply to your modified version as 33 | dnl well. 34 | 35 | dnl Check if the flag is supported by compiler 36 | dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 37 | 38 | AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ 39 | AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), 40 | [ac_save_CFLAGS="$CFLAGS" 41 | CFLAGS="$CFLAGS $1" 42 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])], 43 | [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], 44 | [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) 45 | CFLAGS="$ac_save_CFLAGS" 46 | ]) 47 | 48 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 49 | [$2], [$3]) 50 | ]) 51 | 52 | dnl Check if the flag is supported by compiler (cacheable) 53 | dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 54 | 55 | AC_DEFUN([CC_CHECK_CFLAGS], [ 56 | AC_CACHE_CHECK([if $CC supports $1 flag], 57 | AS_TR_SH([cc_cv_cflags_$1]), 58 | CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! 59 | ) 60 | 61 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 62 | [$2], [$3]) 63 | ]) 64 | 65 | dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) 66 | dnl Check for CFLAG and appends them to CFLAGS if supported 67 | AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ 68 | AC_CACHE_CHECK([if $CC supports $1 flag], 69 | AS_TR_SH([cc_cv_cflags_$1]), 70 | CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! 71 | ) 72 | 73 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 74 | [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3]) 75 | ]) 76 | 77 | dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) 78 | AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ 79 | for flag in $1; do 80 | CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) 81 | done 82 | ]) 83 | 84 | dnl Check if the flag is supported by linker (cacheable) 85 | dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 86 | 87 | AC_DEFUN([CC_CHECK_LDFLAGS], [ 88 | AC_CACHE_CHECK([if $CC supports $1 flag], 89 | AS_TR_SH([cc_cv_ldflags_$1]), 90 | [ac_save_LDFLAGS="$LDFLAGS" 91 | LDFLAGS="$LDFLAGS $1" 92 | AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])], 93 | [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], 94 | [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) 95 | LDFLAGS="$ac_save_LDFLAGS" 96 | ]) 97 | 98 | AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], 99 | [$2], [$3]) 100 | ]) 101 | 102 | dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for 103 | dnl the current linker to avoid undefined references in a shared object. 104 | AC_DEFUN([CC_NOUNDEFINED], [ 105 | dnl We check $host for which systems to enable this for. 106 | AC_REQUIRE([AC_CANONICAL_HOST]) 107 | 108 | case $host in 109 | dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads 110 | dnl are requested, as different implementations are present; to avoid problems 111 | dnl use -Wl,-z,defs only for those platform not behaving this way. 112 | dnl 113 | dnl MinGW platforms: for libraries required -no-undefined, 114 | dnl use it only for libraries in mingw32-w64 115 | 116 | *-freebsd* | *-openbsd*) ;; 117 | *-mingw*) 118 | LDFLAGS_NOUNDEFINED="-no-undefined" 119 | ;; 120 | *) 121 | dnl First of all check for the --no-undefined variant of GNU ld. This allows 122 | dnl for a much more readable commandline, so that people can understand what 123 | dnl it does without going to look for what the heck -z defs does. 124 | for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do 125 | CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) 126 | if test "x$LDFLAGS_NOUNDEFINED" = "x"; then break; fi 127 | done 128 | ;; 129 | esac 130 | 131 | AC_SUBST([LDFLAGS_NOUNDEFINED]) 132 | ]) 133 | 134 | dnl Check for a -Werror flag or equivalent. -Werror is the GCC 135 | dnl and ICC flag that tells the compiler to treat all the warnings 136 | dnl as fatal. We usually need this option to make sure that some 137 | dnl constructs (like attributes) are not simply ignored. 138 | dnl 139 | dnl Other compilers don't support -Werror per se, but they support 140 | dnl an equivalent flag: 141 | dnl - Sun Studio compiler supports -errwarn=%all 142 | AC_DEFUN([CC_CHECK_WERROR], [ 143 | AC_CACHE_CHECK( 144 | [for $CC way to treat warnings as errors], 145 | [cc_cv_werror], 146 | [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], 147 | [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) 148 | ]) 149 | ]) 150 | 151 | AC_DEFUN([CC_CHECK_ATTRIBUTE], [ 152 | AC_REQUIRE([CC_CHECK_WERROR]) 153 | AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], 154 | AS_TR_SH([cc_cv_attribute_$1]), 155 | [ac_save_CFLAGS="$CFLAGS" 156 | CFLAGS="$CFLAGS $cc_cv_werror" 157 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], 158 | [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], 159 | [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) 160 | CFLAGS="$ac_save_CFLAGS" 161 | ]) 162 | 163 | AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], 164 | [AC_DEFINE( 165 | AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, 166 | [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] 167 | ) 168 | $4], 169 | [$5]) 170 | ]) 171 | 172 | AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ 173 | CC_CHECK_ATTRIBUTE( 174 | [constructor],, 175 | [void __attribute__((constructor)) ctor() { int a; }], 176 | [$1], [$2]) 177 | ]) 178 | 179 | AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ 180 | CC_CHECK_ATTRIBUTE( 181 | [format], [format(printf, n, n)], 182 | [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], 183 | [$1], [$2]) 184 | ]) 185 | 186 | AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ 187 | CC_CHECK_ATTRIBUTE( 188 | [format_arg], [format_arg(printf)], 189 | [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], 190 | [$1], [$2]) 191 | ]) 192 | 193 | AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ 194 | CC_CHECK_ATTRIBUTE( 195 | [visibility_$1], [visibility("$1")], 196 | [void __attribute__((visibility("$1"))) $1_function() { }], 197 | [$2], [$3]) 198 | ]) 199 | 200 | AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ 201 | CC_CHECK_ATTRIBUTE( 202 | [nonnull], [nonnull()], 203 | [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], 204 | [$1], [$2]) 205 | ]) 206 | 207 | AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ 208 | CC_CHECK_ATTRIBUTE( 209 | [unused], , 210 | [void some_function(void *foo, __attribute__((unused)) void *bar);], 211 | [$1], [$2]) 212 | ]) 213 | 214 | AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ 215 | CC_CHECK_ATTRIBUTE( 216 | [sentinel], , 217 | [void some_function(void *foo, ...) __attribute__((sentinel));], 218 | [$1], [$2]) 219 | ]) 220 | 221 | AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ 222 | CC_CHECK_ATTRIBUTE( 223 | [deprecated], , 224 | [void some_function(void *foo, ...) __attribute__((deprecated));], 225 | [$1], [$2]) 226 | ]) 227 | 228 | AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ 229 | CC_CHECK_ATTRIBUTE( 230 | [alias], [weak, alias], 231 | [void other_function(void *foo) { } 232 | void some_function(void *foo) __attribute__((weak, alias("other_function")));], 233 | [$1], [$2]) 234 | ]) 235 | 236 | AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ 237 | CC_CHECK_ATTRIBUTE( 238 | [malloc], , 239 | [void * __attribute__((malloc)) my_alloc(int n);], 240 | [$1], [$2]) 241 | ]) 242 | 243 | AC_DEFUN([CC_ATTRIBUTE_PACKED], [ 244 | CC_CHECK_ATTRIBUTE( 245 | [packed], , 246 | [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], 247 | [$1], [$2]) 248 | ]) 249 | 250 | AC_DEFUN([CC_ATTRIBUTE_CONST], [ 251 | CC_CHECK_ATTRIBUTE( 252 | [const], , 253 | [int __attribute__((const)) twopow(int n) { return 1 << n; } ], 254 | [$1], [$2]) 255 | ]) 256 | 257 | AC_DEFUN([CC_FLAG_VISIBILITY], [ 258 | AC_REQUIRE([CC_CHECK_WERROR]) 259 | AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], 260 | [cc_cv_flag_visibility], 261 | [cc_flag_visibility_save_CFLAGS="$CFLAGS" 262 | CFLAGS="$CFLAGS $cc_cv_werror" 263 | CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], 264 | cc_cv_flag_visibility='yes', 265 | cc_cv_flag_visibility='no') 266 | CFLAGS="$cc_flag_visibility_save_CFLAGS"]) 267 | 268 | AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], 269 | [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, 270 | [Define this if the compiler supports the -fvisibility flag]) 271 | $1], 272 | [$2]) 273 | ]) 274 | 275 | AC_DEFUN([CC_FUNC_EXPECT], [ 276 | AC_REQUIRE([CC_CHECK_WERROR]) 277 | AC_CACHE_CHECK([if compiler has __builtin_expect function], 278 | [cc_cv_func_expect], 279 | [ac_save_CFLAGS="$CFLAGS" 280 | CFLAGS="$CFLAGS $cc_cv_werror" 281 | AC_COMPILE_IFELSE( 282 | [int some_function() { 283 | int a = 3; 284 | return (int)__builtin_expect(a, 3); 285 | }], 286 | [cc_cv_func_expect=yes], 287 | [cc_cv_func_expect=no]) 288 | CFLAGS="$ac_save_CFLAGS" 289 | ]) 290 | 291 | AS_IF([test "x$cc_cv_func_expect" = "xyes"], 292 | [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, 293 | [Define this if the compiler supports __builtin_expect() function]) 294 | $1], 295 | [$2]) 296 | ]) 297 | 298 | AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ 299 | AC_REQUIRE([CC_CHECK_WERROR]) 300 | AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], 301 | [cc_cv_attribute_aligned], 302 | [ac_save_CFLAGS="$CFLAGS" 303 | CFLAGS="$CFLAGS $cc_cv_werror" 304 | for cc_attribute_align_try in 64 32 16 8 4 2; do 305 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([ 306 | int main() { 307 | static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; 308 | return c; 309 | }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) 310 | done 311 | CFLAGS="$ac_save_CFLAGS" 312 | ]) 313 | 314 | if test "x$cc_cv_attribute_aligned" != "x"; then 315 | AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], 316 | [Define the highest alignment supported]) 317 | fi 318 | ]) 319 | -------------------------------------------------------------------------------- /maemo/98-maemo.conf: -------------------------------------------------------------------------------- 1 | pcm.!default { 2 | type alsa_dsp 3 | playback_device_file [ "/dev/dsptask/pcm2" ] 4 | recording_device_file [ "/dev/dsptask/pcm_rec" ] 5 | } 6 | 7 | ctl.!default { 8 | type dsp_ctl 9 | playback_devices [ "/dev/dsptask/pcm2" ] 10 | recording_devices [ "/dev/dsptask/pcm_rec" ] 11 | } 12 | -------------------------------------------------------------------------------- /maemo/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 98-maemo.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_alsa_dsp_LTLIBRARIES = libasound_module_pcm_alsa_dsp.la 6 | asound_module_ctl_dsp_ctl_LTLIBRARIES = libasound_module_ctl_dsp_ctl.la 7 | asound_module_gconf_DATA = $(GCONF_FILES) 8 | 9 | asound_module_pcm_alsa_dspdir = @ALSA_PLUGIN_DIR@ 10 | asound_module_ctl_dsp_ctldir = @ALSA_PLUGIN_DIR@ 11 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 12 | 13 | AM_CFLAGS = -Wall -O2 @ALSA_CFLAGS@ $(DBUS_CFLAGS) 14 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 15 | 16 | libasound_module_pcm_alsa_dsp_la_SOURCES = dsp-protocol.c alsa-dsp.c 17 | libasound_module_pcm_alsa_dsp_la_LIBADD = @ALSA_LIBS@ $(DBUS_LIBS) -lpthread 18 | 19 | libasound_module_ctl_dsp_ctl_la_SOURCES = dsp-protocol.c dsp-ctl.c 20 | libasound_module_ctl_dsp_ctl_la_LIBADD = @ALSA_LIBS@ $(DBUS_LIBS) -lpthread 21 | 22 | noinst_HEADERS = constants.h debug.h dsp-protocol.h list.h reporting.h \ 23 | types.h 24 | 25 | include ../install-hooks.am 26 | 27 | install-data-hook: install-conf-hook 28 | 29 | uninstall-local: uninstall-conf-hook 30 | -------------------------------------------------------------------------------- /maemo/constants.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file constants.h 3 | * @brief PCM Task node protocol constants definition 4 | *

5 | * Copyright (C) 2006 Nokia Corporation 6 | *

7 | * Contact: Eduardo Bezerra Valentin 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Library General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Library General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Library General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | * */ 23 | #ifndef _CONSTANTS_H 24 | #define _CONSTANTS_H 25 | /** 26 | * Commands 27 | * */ 28 | /** No command */ 29 | #define DSP_CMD_NONE 0x00 30 | /** Informs the DSP that the following data is about initialisation. */ 31 | #define DSP_CMD_INIT 0x01 32 | /** Informs the DSP that the following data is parameters */ 33 | #define DSP_CMD_SET_PARAMS 0x02 34 | /** Informs the DSP that the following data is general data (compressed 35 | * or raw audio or video) 36 | * */ 37 | #define DSP_CMD_DATA_WRITE 0x03 38 | /** Starts audio or video playback or recording */ 39 | #define DSP_CMD_PLAY 0x04 40 | /** Pauses playback */ 41 | #define DSP_CMD_PAUSE 0x05 42 | /** Stops playback */ 43 | #define DSP_CMD_STOP 0x06 44 | /** Informs the DSP that the following data is volume */ 45 | #define DSP_CMD_SET_VOLUME 0x07 46 | /** Requests from the DSP to send information about current task node 47 | * state 48 | * */ 49 | #define DSP_CMD_STATE 0x08 50 | /** Informs the DSP that the following data is about setting the current 51 | * presentation time 52 | * */ 53 | #define DSP_CMD_SET_TIME 0x09 54 | /** Informs the DSP that the ARM queries the current presentation time */ 55 | #define DSP_CMD_GET_TIME 0x0A 56 | /** Informs the DSP that the following data is about setting video 57 | * post-processing parameters 58 | * */ 59 | #define DSP_CMD_SET_POSTPROC 0x0B 60 | /** Informs the DSP that the following data is about setting the panning 61 | * */ 62 | #define DSP_CMD_SET_PANNING 0x0D 63 | /** Informs the DSP about discontinuity in the audio stream */ 64 | #define DSP_CMD_DISCONT 0x0E 65 | /** Mutes the audio playback */ 66 | #define DSP_CMD_MUTE 0x0F 67 | /** Unmutes the audio playback */ 68 | #define DSP_CMD_UNMUTE 0x10 69 | /**Closes the task node*/ 70 | #define DSP_CMD_CLOSE 0x14 71 | /** Command from DSP to start to read data*/ 72 | #define DSP_CMD_DATA_READ 0x25 73 | /**Sets speech parameters*/ 74 | #define DSP_CMD_SET_SPEECH_PARAMS 0x26 75 | 76 | /** 77 | * Audio formats 78 | * */ 79 | /** Unsigned 8 bits per sample PCM */ 80 | #define DSP_AFMT_U8 0x01 81 | /** Signed 16 bits per sample PCM, little endian */ 82 | #define DSP_AFMT_S16_LE 0x02 83 | /** Signed 16 bits per sample PCM, big endian */ 84 | #define DSP_AFMT_S16_BE 0x03 85 | /** Signed 8 bits per sample PCM */ 86 | #define DSP_AFMT_S8 0x04 87 | /** Unsigned 16 bits per sample PCM, little endian */ 88 | #define DSP_AFMT_U16_LE 0x05 89 | /** Unsigned 16 bits per sample PCM, big endian */ 90 | #define DSP_AFMT_U16_BE 0x06 91 | /** A-law encoded PCM */ 92 | #define DSP_AFMT_ALAW 0x07 93 | /** μ-Law encoded PCM */ 94 | #define DSP_AFMT_ULAW 0x08 95 | /** MP3 stream */ 96 | #define DSP_AFMT_MP3 0x09 97 | /** AAC stream */ 98 | #define DSP_AFMT_AAC 0x0A 99 | /** AMR stream */ 100 | #define DSP_AFMT_AMR 0x0B 101 | /** MP2 stream */ 102 | #define DSP_AFMT_MP2 0x0C 103 | /** iLBC stream */ 104 | #define DSP_AFMT_ILBC 0x0D 105 | /** G.729 stream */ 106 | #define DSP_AFMT_G729 0x0E 107 | /** 108 | * Supported Sample rates 109 | * */ 110 | /** 96KHz sampling rate */ 111 | #define SAMPLE_RATE_96KHZ 0x00 112 | /** 88.2KHz sampling rate */ 113 | #define SAMPLE_RATE_88_2KHZ 0x01 114 | /** 64KHz sampling rate */ 115 | #define SAMPLE_RATE_64KHZ 0x02 116 | /** 48KHz sampling rate */ 117 | #define SAMPLE_RATE_48KHZ 0x03 118 | /** 44.1KHz sampling rate */ 119 | #define SAMPLE_RATE_44_1KHZ 0x04 120 | /** 32KHz sampling rate */ 121 | #define SAMPLE_RATE_32KHZ 0x05 122 | /** 24KHz sampling rate */ 123 | #define SAMPLE_RATE_24KHZ 0x06 124 | /** 22.05KHz sampling rate */ 125 | #define SAMPLE_RATE_22_05KHZ 0x07 126 | /** 16KHz sampling rate */ 127 | #define SAMPLE_RATE_16KHZ 0x08 128 | /** 12KHz sampling rate */ 129 | #define SAMPLE_RATE_12KHZ 0x09 130 | /** 11.025KHz sampling rate */ 131 | #define SAMPLE_RATE_11_025KHZ 0x0A 132 | /** 8KHz sampling rate */ 133 | #define SAMPLE_RATE_8KHZ 0x0B 134 | /** 5.5125Khz sampling rate */ 135 | #define SAMPLE_RATE_5_5125KHZ 0X0C 136 | /** 137 | * DSP Return values 138 | * */ 139 | /** Operation successful */ 140 | #define DSP_OK 0x01 141 | /** Unrecognised or unsupported command value */ 142 | #define DSP_ERROR_CMD 0x02 143 | /** Unrecognised or unsupported audio format value */ 144 | #define DSP_ERROR_FMT 0x03 145 | /** Unrecognised or unsupported sampling rate value */ 146 | #define DSP_ERROR_RATE 0x04 147 | /** Unrecognised or unsupported number of channels */ 148 | #define DSP_ERROR_CHANNELS 0x05 149 | /** Destination/source stream ID out of range */ 150 | #define DSP_ERROR_DS_ID 0x06 151 | /** Insufficient memory to perform requested action */ 152 | #define DSP_ERROR_MEMORY 0x07 153 | /** Unspecified error */ 154 | #define DSP_ERROR_GENERAL 0x08 155 | /** Error in stream (audio or video) */ 156 | #define DSP_ERROR_STREAM 0x09 157 | /** Unexpected task node state */ 158 | #define DSP_ERROR_STATE 0x0A 159 | /** Error in synchronisation: 160 | For MP3 – synchronisation marker not found */ 161 | #define DSP_ERROR_SYNC 0x0B 162 | /** For MPEG4: non-compliant video stream */ 163 | #define DSP_ERROR_VIDEO_NON_COMPLIANT 0x100 164 | /** For MPEG4: Error in VOS */ 165 | #define DSP_ERROR_VIDEO_FAULT_IN_VOS 0x101 166 | /** For MPEG4: Image size not supported */ 167 | #define DSP_ERROR_VIDEO_SIZE_NOT_SUPPORTED 0x102 168 | /** End of VOS code reached */ 169 | #define DSP_ERROR_VIDEO_VOS_END_CODE 0x103 170 | /** 171 | * Channels 172 | * */ 173 | /** One channel (mono) */ 174 | #define CHANNELS_1 0x01 175 | /** Two channels (stereo) */ 176 | #define CHANNELS_2 0x02 177 | /** 178 | * Audio Task node states 179 | * */ 180 | /** Initialised */ 181 | #define STATE_INITIALISED 0x00 182 | /** Playing/recording */ 183 | #define STATE_PLAYING 0x01 184 | /** Stopped */ 185 | #define STATE_STOPPED 0x02 186 | /** Paused */ 187 | #define STATE_PAUSED 0x03 188 | /** Not initialised */ 189 | #define STATE_UNINITIALISED 0x04 190 | /** Reseted */ 191 | #define STATE_RESET 0x05 192 | /** Muted */ 193 | #define STATE_MUTED 0x06 194 | 195 | /** Sending commands */ 196 | #define REQUEST_CONFIRMATION 0x01 197 | #define WITHOU_CONFIRMATION 0x00 198 | #endif /* _CONSTANTS_H */ 199 | -------------------------------------------------------------------------------- /maemo/debug.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file debug.h 3 | * @brief Debugging Macros 4 | *

5 | * Copyright (C) 2006 Nokia Corporation 6 | *

7 | * Contact: Eduardo Bezerra Valentin 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Library General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Library General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Library General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | * */ 23 | #ifndef _DEBUG_H 24 | #define _DEBUG_H 25 | 26 | //#define DEBUG 27 | #undef DEBUG 28 | #ifdef DEBUG 29 | #define DEBUG_OUTPUT stderr 30 | #define DPRINT(fmt,arg...) fprintf(DEBUG_OUTPUT, "%s(): " fmt,\ 31 | __FUNCTION__, ##arg) 32 | #define DENTER() fprintf(DEBUG_OUTPUT, "ENTER %s()\n", __FUNCTION__) 33 | #define DLEAVE(a) fprintf(DEBUG_OUTPUT, "LEAVE %s() %d\n", __FUNCTION__, a) 34 | #else 35 | #define DPRINT(fmt,arg...) do { } while (0) 36 | #define DENTER() do { } while (0) 37 | #define DLEAVE(a) do { } while (0) 38 | #endif 39 | 40 | /* Errors on/off */ 41 | #define ERROR_DEBUG 42 | /* #undef ERROR_DEBUG */ 43 | #ifdef ERROR_DEBUG 44 | #define DERROR(fmt,arg...) fprintf(stderr, "%s(): " fmt, \ 45 | __FUNCTION__, ##arg) 46 | #else 47 | #define DERROR(fmt,arg...) \ 48 | do { } while (0) 49 | #endif 50 | 51 | #endif /* _DEBUG_H */ 52 | -------------------------------------------------------------------------------- /maemo/dsp-protocol.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dsp-protocol.h - Definition of functions whose represents 3 | * an interface to the DSP PCM Task node protocol. 4 | *

5 | * Copyright (C) 2006 Nokia Corporation 6 | *

7 | * Contact: Eduardo Bezerra Valentin 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Library General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Library General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Library General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | * */ 23 | #ifndef _DSP_PROTOCOL_H 24 | #define _DSP_PROTOCOL_H 25 | 26 | #define __USE_GNU 27 | #include 28 | #include 29 | #include 30 | #include "types.h" 31 | 32 | #ifdef HAVE_CONFIG_H 33 | #include 34 | #endif 35 | 36 | 37 | typedef struct { 38 | int fd; 39 | char *device; 40 | int state; 41 | int mute; 42 | unsigned int stream_id; 43 | unsigned int bridge_buffer_size; /* in bytes */ 44 | unsigned int mmap_buffer_size; /* in bytes */ 45 | short int *mmap_buffer; 46 | pthread_mutex_t mutex; 47 | int sem_set_id; 48 | #ifdef USE_RESOURCE_MANAGER 49 | void *dbus_connection; 50 | #endif 51 | } dsp_protocol_t; 52 | /* Initialisation phase */ 53 | int dsp_protocol_create(dsp_protocol_t ** dsp_protocol); 54 | int dsp_protocol_open_node(dsp_protocol_t * dsp_protocol, const char *device); 55 | int dsp_protocol_send_audio_params(dsp_protocol_t * dsp_protocol, 56 | audio_params_data_t * audio_params_data); 57 | int dsp_protocol_send_speech_params(dsp_protocol_t * dsp_protocol, 58 | speech_params_data_t * audio_params_data); 59 | 60 | /* Execution phase */ 61 | int dsp_protocol_send_play(dsp_protocol_t * dsp_protocol); 62 | int dsp_protocol_send_audio_data(dsp_protocol_t * dsp_protocol, 63 | void *data, unsigned short int count); 64 | int dsp_protocol_receive_audio_data(dsp_protocol_t * dsp_protocol, 65 | void *data, int count); 66 | 67 | int dsp_protocol_send_pause(dsp_protocol_t * dsp_protocol); 68 | int dsp_protocol_send_stop(dsp_protocol_t * dsp_protocol); 69 | 70 | /* Deletion phase */ 71 | int dsp_protocol_close_node(dsp_protocol_t * dsp_protocol); 72 | int dsp_protocol_destroy(dsp_protocol_t ** dsp_protocol); 73 | 74 | /* controls */ 75 | int dsp_protocol_set_volume(dsp_protocol_t * dsp_protocol, 76 | unsigned char left, unsigned char right); 77 | int dsp_protocol_get_volume(dsp_protocol_t * dsp_protocol, 78 | unsigned char *left, unsigned char *right); 79 | int dsp_protocol_set_mute(dsp_protocol_t * dsp_protocol, unsigned char mute); 80 | int dsp_protocol_get_mute(dsp_protocol_t * dsp_protocol); 81 | 82 | /*miscelaneos*/ 83 | int dsp_protocol_set_mic_enabled(dsp_protocol_t * dsp_protocol, int enabled); 84 | int dsp_protocol_probe_node(dsp_protocol_t * dsp_protocol, const char *device); 85 | int safe_strtol(const char *str, long *val); 86 | 87 | #endif /* _DSP_PROTOCOL_H */ 88 | -------------------------------------------------------------------------------- /maemo/list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H 2 | #define __LIST_H 3 | 4 | /* This file is from Linux Kernel (include/linux/list.h) 5 | * and modified by simply removing hardware prefetching of list items. 6 | * Here by copyright, credits attributed to wherever they belong. 7 | * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) 8 | */ 9 | 10 | /* 11 | * Simple doubly linked list implementation. 12 | * 13 | * Some of the internal functions ("__xxx") are useful when 14 | * manipulating whole lists rather than single entries, as 15 | * sometimes we already know the next/prev entries and we can 16 | * generate better code by using them directly rather than 17 | * using the generic single-entry routines. 18 | */ 19 | 20 | struct list_head { 21 | struct list_head *next, *prev; 22 | }; 23 | 24 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 25 | 26 | #define LIST_HEAD(name) \ 27 | struct list_head name = LIST_HEAD_INIT(name) 28 | 29 | #define INIT_LIST_HEAD(ptr) do { \ 30 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 31 | } while (0) 32 | 33 | /* 34 | * Insert a new entry between two known consecutive entries. 35 | * 36 | * This is only for internal list manipulation where we know 37 | * the prev/next entries already! 38 | */ 39 | static inline void __list_add(struct list_head *new, 40 | struct list_head *prev, 41 | struct list_head *next) 42 | { 43 | next->prev = new; 44 | new->next = next; 45 | new->prev = prev; 46 | prev->next = new; 47 | } 48 | 49 | /** 50 | * list_add - add a new entry 51 | * @new: new entry to be added 52 | * @head: list head to add it after 53 | * 54 | * Insert a new entry after the specified head. 55 | * This is good for implementing stacks. 56 | */ 57 | static inline void list_add(struct list_head *new, struct list_head *head) 58 | { 59 | __list_add(new, head, head->next); 60 | } 61 | 62 | /** 63 | * list_add_tail - add a new entry 64 | * @new: new entry to be added 65 | * @head: list head to add it before 66 | * 67 | * Insert a new entry before the specified head. 68 | * This is useful for implementing queues. 69 | */ 70 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 71 | { 72 | __list_add(new, head->prev, head); 73 | } 74 | 75 | /* 76 | * Delete a list entry by making the prev/next entries 77 | * point to each other. 78 | * 79 | * This is only for internal list manipulation where we know 80 | * the prev/next entries already! 81 | */ 82 | static inline void __list_del(struct list_head *prev, struct list_head *next) 83 | { 84 | next->prev = prev; 85 | prev->next = next; 86 | } 87 | 88 | /** 89 | * list_del - deletes entry from list. 90 | * @entry: the element to delete from the list. 91 | * Note: list_empty on entry does not return true after this, the entry is in an undefined state. 92 | */ 93 | static inline void list_del(struct list_head *entry) 94 | { 95 | __list_del(entry->prev, entry->next); 96 | entry->next = (void *) 0; 97 | entry->prev = (void *) 0; 98 | } 99 | 100 | /** 101 | * list_del_init - deletes entry from list and reinitialize it. 102 | * @entry: the element to delete from the list. 103 | */ 104 | static inline void list_del_init(struct list_head *entry) 105 | { 106 | __list_del(entry->prev, entry->next); 107 | INIT_LIST_HEAD(entry); 108 | } 109 | 110 | /** 111 | * list_move - delete from one list and add as another's head 112 | * @list: the entry to move 113 | * @head: the head that will precede our entry 114 | */ 115 | static inline void list_move(struct list_head *list, struct list_head *head) 116 | { 117 | __list_del(list->prev, list->next); 118 | list_add(list, head); 119 | } 120 | 121 | /** 122 | * list_move_tail - delete from one list and add as another's tail 123 | * @list: the entry to move 124 | * @head: the head that will follow our entry 125 | */ 126 | static inline void list_move_tail(struct list_head *list, 127 | struct list_head *head) 128 | { 129 | __list_del(list->prev, list->next); 130 | list_add_tail(list, head); 131 | } 132 | 133 | /** 134 | * list_empty - tests whether a list is empty 135 | * @head: the list to test. 136 | */ 137 | static inline int list_empty(struct list_head *head) 138 | { 139 | return head->next == head; 140 | } 141 | 142 | static inline void __list_splice(struct list_head *list, 143 | struct list_head *head) 144 | { 145 | struct list_head *first = list->next; 146 | struct list_head *last = list->prev; 147 | struct list_head *at = head->next; 148 | 149 | first->prev = head; 150 | head->next = first; 151 | 152 | last->next = at; 153 | at->prev = last; 154 | } 155 | 156 | /** 157 | * list_splice - join two lists 158 | * @list: the new list to add. 159 | * @head: the place to add it in the first list. 160 | */ 161 | static inline void list_splice(struct list_head *list, struct list_head *head) 162 | { 163 | if (!list_empty(list)) 164 | __list_splice(list, head); 165 | } 166 | 167 | /** 168 | * list_splice_init - join two lists and reinitialise the emptied list. 169 | * @list: the new list to add. 170 | * @head: the place to add it in the first list. 171 | * 172 | * The list at @list is reinitialised 173 | */ 174 | static inline void list_splice_init(struct list_head *list, 175 | struct list_head *head) 176 | { 177 | if (!list_empty(list)) { 178 | __list_splice(list, head); 179 | INIT_LIST_HEAD(list); 180 | } 181 | } 182 | 183 | /** 184 | * list_entry - get the struct for this entry 185 | * @ptr: the &struct list_head pointer. 186 | * @type: the type of the struct this is embedded in. 187 | * @member: the name of the list_struct within the struct. 188 | */ 189 | #define list_entry(ptr, type, member) \ 190 | ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) 191 | 192 | /** 193 | * list_for_each - iterate over a list 194 | * @pos: the &struct list_head to use as a loop counter. 195 | * @head: the head for your list. 196 | */ 197 | #define list_for_each(pos, head) \ 198 | for (pos = (head)->next; pos != (head); \ 199 | pos = pos->next) 200 | /** 201 | * list_for_each_prev - iterate over a list backwards 202 | * @pos: the &struct list_head to use as a loop counter. 203 | * @head: the head for your list. 204 | */ 205 | #define list_for_each_prev(pos, head) \ 206 | for (pos = (head)->prev; pos != (head); \ 207 | pos = pos->prev) 208 | 209 | /** 210 | * list_for_each_safe - iterate over a list safe against removal of list entry 211 | * @pos: the &struct list_head to use as a loop counter. 212 | * @n: another &struct list_head to use as temporary storage 213 | * @head: the head for your list. 214 | */ 215 | #define list_for_each_safe(pos, n, head) \ 216 | for (pos = (head)->next, n = pos->next; pos != (head); \ 217 | pos = n, n = pos->next) 218 | 219 | /** 220 | * list_for_each_entry - iterate over list of given type 221 | * @pos: the type * to use as a loop counter. 222 | * @head: the head for your list. 223 | * @member: the name of the list_struct within the struct. 224 | */ 225 | #define list_for_each_entry(pos, head, member) \ 226 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 227 | &pos->member != (head); \ 228 | pos = list_entry(pos->member.next, typeof(*pos), member)) 229 | 230 | /** 231 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 232 | * @pos: the type * to use as a loop counter. 233 | * @n: another type * to use as temporary storage 234 | * @head: the head for your list. 235 | * @member: the name of the list_struct within the struct. 236 | */ 237 | #define list_for_each_entry_safe(pos, n, head, member) \ 238 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 239 | n = list_entry(pos->member.next, typeof(*pos), member); \ 240 | &pos->member != (head); \ 241 | pos = n, n = list_entry(n->member.next, typeof(*n), member)) 242 | 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /maemo/reporting.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file reporting.h - Definition of functions whose represents an interface 3 | * to report errors. 4 | *

5 | * Copyright (C) 2006 Nokia Corporation 6 | *

7 | * Contact: Eduardo Bezerra Valentin 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Library General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Library General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Library General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | * */ 23 | #ifndef _REPORTING_H 24 | #define _REPORTING_H 25 | #include "dsp-protocol.h" 26 | 27 | #ifdef DEBUG 28 | const char *dsp_commands[] = { 29 | "DSP_CMD_NONE", "No command", 30 | "DSP_CMD_INIT", "Informs the DSP that the following data is" 31 | "about initialisation", 32 | "DSP_CMD_SET_PARAMS", "Informs the DSP that the following " 33 | "data is parameters", 34 | "DSP_CMD_DATA_WRITE", "Informs the DSP that the following " 35 | "data is general data (compressed " "or raw audio or video)", 36 | "DSP_CMD_PLAY", "Starts audio or video playback or recording", 37 | "DSP_CMD_PAUSE", "Pauses playback", 38 | "DSP_CMD_STOP", "Stops playback", 39 | "DSP_CMD_SET_VOLUME", "Informs the DSP that the following " 40 | "data is volume", 41 | "DSP_CMD_STATE", "Requests from the DSP to send information" 42 | " about current task node state", 43 | "DSP_CMD_SET_TIME", "Informs the DSP that the following data" 44 | " is about setting the current" " presentation time", 45 | "DSP_CMD_GET_TIME", "Informs the DSP that the ARM queries the" 46 | " current presentation time", 47 | "ERROR", "This is unused!!!!!", 48 | "DSP_CMD_SET_POSTPROC", "Informs the DSP that the following data" 49 | " is about setting video post-processing " "parameters", 50 | "DSP_CMD_SET_PANNING", "Informs the DSP that the following data " 51 | "is about setting the panning", 52 | "DSP_CMD_DISCONT", "Informs the DSP about discontinuity in the " 53 | "audio stream", 54 | "DSP_CMD_MUTE", "Mutes the audio playback", 55 | "DSP_CMD_UNMUTE", "Unmutes the audio playback", 56 | "ERROR", "This is unused!!!!!", 57 | "ERROR", "This is unused!!!!!", 58 | "ERROR", "This is unused!!!!!", 59 | "DSP_CMD_CLOSE", "Closes the task node" 60 | }; 61 | 62 | const char *dsp_return_values[] = { 63 | "DSP_NONE", "Error. This isn't a valid return value", 64 | "DSP_OK", "Operation successful", 65 | "DSP_ERROR_CMD", "Unrecognised or unsupported command value", 66 | "DSP_ERROR_FMT", "Unrecognised or unsupported audio format value", 67 | "DSP_ERROR_RATE", "Unrecognised or unsupported sampling rate value", 68 | "DSP_ERROR_CHANNELS", "Unrecognised or unsupported number of channels", 69 | "DSP_ERROR_DS_id", "Destination/source stream id out of range", 70 | "DSP_ERROR_MEMORY", "Insufficient memory to perform requested action", 71 | "DSP_ERROR_GENERAL", "Unspecified error", 72 | "DSP_ERROR_STREAM", "Error in stream (audio or video)", 73 | "DSP_ERROR_STATE", "Unexpected task node state", 74 | "DSP_ERROR_SYNC", "Error in synchronisation:" 75 | "For MP3 – synchronisation marker not found" 76 | }; 77 | 78 | const char *dsp_states[] = { 79 | "STATE_INITIALISED", "Initialised", 80 | "STATE_PLAYING", "Playing/recording", 81 | "STATE_STOPPED", "Stopped", 82 | "STATE_PAUSED", "Paused", 83 | "STATE_UNINITIALISED", "Not initialised", 84 | "STATE_RESET", "Reseted", 85 | "STATE_MUTED", "Muted" 86 | }; 87 | 88 | const char *dsp_rates[] = { 89 | "SAMPLE_RATE_96KHZ", "96KHz sampling rate", 90 | "SAMPLE_RATE_88_2KHZ", "88.2KHz sampling rate", 91 | "SAMPLE_RATE_64KHZ", "64KHz sampling rate", 92 | "SAMPLE_RATE_48KHZ", "48KHz sampling rate", 93 | "SAMPLE_RATE_44_1KHZ", "44.1KHz sampling rate", 94 | "SAMPLE_RATE_32KHZ", "32KHz sampling rate", 95 | "SAMPLE_RATE_24KHZ", "24KHz sampling rate", 96 | "SAMPLE_RATE_22_05KHZ", "22.05KHz sampling rate", 97 | "SAMPLE_RATE_16KHZ", "16KHz sampling rate", 98 | "SAMPLE_RATE_12KHZ", "12KHz sampling rate", 99 | "SAMPLE_RATE_11_025KHZ", "11.025KHz sampling rate", 100 | "SAMPLE_RATE_8KHZ", "8KHz sampling rate", 101 | "SAMPLE_RATE_5_5125KHZ", "5.5125Khz sampling rate" 102 | }; 103 | 104 | const char *dsp_channels[] = { 105 | "0--", "Error - No channel!", 106 | "CHANNELS_1", "One channel (mono)", 107 | "CHANNELS_2", "Two channels (stereo)" 108 | }; 109 | 110 | const char *dsp_audio_fmt[] = { 111 | "0", "Error No format!!!", 112 | "DSP_AFMT_U8", "Unsigned 8 bits per sample PCM", 113 | "DSP_AFMT_S16_LE", "Signed 16 bits per sample PCM, little endian", 114 | "DSP_AFMT_S16_BE", "Signed 16 bits per sample PCM, big endian", 115 | "DSP_AFMT_S8", "Signed 8 bits per sample PCM", 116 | "DSP_AFMT_U16_LE", "Unsigned 16 bits per sample PCM, little endian", 117 | "DSP_AFMT_U16_BE", "Unsigned 16 bits per sample PCM, big endian", 118 | "DSP_AFMT_ALAW", "A-law encoded PCM", 119 | "DSP_AFMT_ULAW", "μ-Law encoded PCM", 120 | "DSP_AFMT_MP3", "MP3 stream", 121 | "DSP_AFMT_AAC", "AAC stream", 122 | "DSP_AFMT_AMR", "AMR stream", 123 | "DSP_AFMT_MP2", "MP2 stream", 124 | "DSP_AFMT_ILBC", "iLBC stream", 125 | "DSP_AFMT_G729", "G.729 stream" 126 | }; 127 | 128 | #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) 129 | #define report_table(mens,name,value,table)\ 130 | do{\ 131 | if ((unsigned)value >= ARRAY_SIZE(table))\ 132 | DPRINT("%s: %d isnt a valid %s value\n",mens,\ 133 | value,name);\ 134 | else\ 135 | DPRINT("%s: [%d|%s] - %s\n", mens, value, \ 136 | table[value * 2], \ 137 | table[value * 2 + 1]);\ 138 | }while(0) 139 | 140 | #define report_command(m,v) report_table(m,"command",v,\ 141 | /*20,*/dsp_commands) 142 | #define report_return_value(m,v) report_table(m,"return",v,\ 143 | /*11,*/dsp_return_values) 144 | #define report_state(m,v) report_table(m,"state",v,\ 145 | /*6,*/dsp_states) 146 | #define report_sample_rate(m,v) report_table(m,"sample rate",v,\ 147 | /*12,*/dsp_rates) 148 | #define report_number_channels(m,v) report_table(m,"number of channels",v,\ 149 | /*2,*/dsp_channels) 150 | #define report_audio_fmt(m,v) report_table(m,"audio format",v,\ 151 | /*14,*/dsp_audio_fmt) 152 | #define report_dsp_protocol(m,dp)\ 153 | do{\ 154 | DPRINT("%s:\n"\ 155 | "fd: %d\n"\ 156 | "stream_id: %d\n"\ 157 | "bridge_buffer_size: %d\n"\ 158 | "mmap_buffer_size: %d\n"\ 159 | "mmap_buffer: %p\n",\ 160 | m,\ 161 | dp->fd,\ 162 | dp->stream_id,\ 163 | dp->bridge_buffer_size,\ 164 | dp->mmap_buffer_size,\ 165 | dp->mmap_buffer);\ 166 | report_state("state", dp->state);\ 167 | }while(0) 168 | 169 | #define report_audio_status_info(m, asi)\ 170 | do{\ 171 | DPRINT("%s\n", m);\ 172 | DPRINT("***** Audio status info *****\n");\ 173 | report_command("\tdsp_cmd", asi.dsp_cmd);\ 174 | DPRINT("\tstream_id: %d\n", asi.stream_id);\ 175 | DPRINT("\tds_stream_id: %d\n", asi.ds_stream_id);\ 176 | DPRINT("\tbridge_buffer_size: %d\n", asi.bridge_buffer_size);\ 177 | DPRINT("\tmmap_buffer_size: %d\n", asi.mmap_buffer_size);\ 178 | report_state("\tstatus", asi.status);\ 179 | DPRINT("\tnum_frames: %d\n", asi.num_frames);\ 180 | report_sample_rate("\tsample_rate", asi.sample_rate);\ 181 | report_number_channels("\tnumber_channels", \ 182 | asi.number_channels);\ 183 | DPRINT("\tvol_scale: %d\n", asi.vol_scale);\ 184 | DPRINT("\tvol_power2: %d\n", asi.vol_power2);\ 185 | DPRINT("\tleft_gain: %d\n", asi.left_gain);\ 186 | DPRINT("\tright_gain: %d\n", asi.right_gain);\ 187 | report_audio_fmt("\tdsp_audio_fmt", asi.dsp_audio_fmt);\ 188 | }while(0) 189 | 190 | #define report_audio_init_status(m, ais)\ 191 | do{\ 192 | DPRINT("%s\n", m);\ 193 | DPRINT("***** Audio init status *****\n");\ 194 | report_command("\tdsp_cmd", ais.dsp_cmd);\ 195 | DPRINT("\tstream_id: %d\n", ais.stream_id);\ 196 | DPRINT("\tbridge_buffer_size: %d\n", ais.bridge_buffer_size);\ 197 | DPRINT("\tmmap_buffer_size: %d\n", ais.mmap_buffer_size);\ 198 | report_return_value("\tinit_status", ais.init_status);\ 199 | }while(0) 200 | 201 | #define report_audio_params(m,ap)\ 202 | do{\ 203 | DPRINT("%s\n",m);\ 204 | DPRINT("**** Audio parameters *****\n");\ 205 | report_command("\tdsp_cmd",ap.dsp_cmd);\ 206 | report_audio_fmt("\taudio_format", ap.dsp_audio_fmt);\ 207 | report_sample_rate("\tsample_rate", ap.sample_rate);\ 208 | DPRINT("Number of channels %d\n", ap.number_channels);\ 209 | DPRINT("ds_stream_id: %d\n", ap.ds_stream_id);\ 210 | DPRINT("stream_priority: %d\n", ap.stream_priority);\ 211 | }while(0) 212 | 213 | #define report_speech_params(m,sp)\ 214 | do{\ 215 | DPRINT("%s\n",m);\ 216 | DPRINT("**** Speech parameters *****\n");\ 217 | DPRINT("\tdsp_cmd 0x%x\n",sp.dsp_cmd);\ 218 | report_audio_fmt("\taudio_format", sp.audio_fmt);\ 219 | report_sample_rate("\tsample_rate", sp.sample_rate);\ 220 | DPRINT("ds_stream_id: %d\n", sp.ds_stream_id);\ 221 | DPRINT("stream_priority: %d\n", sp.stream_priority);\ 222 | DPRINT("frame_size: %d\n", sp.frame_size);\ 223 | }while(0) 224 | #else 225 | 226 | #define report_command(m,c) 227 | #define report_return_value(m,c) 228 | #define report_state(m,c) 229 | #define report_sample_rate(m,sr) 230 | #define report_number_channel(m,nc) 231 | #define report_audio_fmt(m,af) 232 | #define report_dsp_protocol(m,dp) 233 | #define report_audio_status_info(m,asi) 234 | #define report_audio_init_status(m,ais) 235 | #define report_audio_params(m,ap) 236 | #define report_speech_params(m,ap) 237 | 238 | #endif /* _DEBUG */ 239 | 240 | #endif /* _REPORTING_H */ 241 | -------------------------------------------------------------------------------- /maemo/types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file types.h - datatypes defined to communicate with PCM task 3 | * node using its protocol. 4 | *

5 | * Copyright (C) 2006 Nokia Corporation 6 | *

7 | * Contact: Eduardo Bezerra Valentin 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Library General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Library General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Library General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | * */ 23 | #ifndef _TYPES_H 24 | #define _TYPES_H 25 | 26 | typedef struct { 27 | unsigned short dsp_cmd; 28 | unsigned short init_status; 29 | unsigned short stream_id; 30 | unsigned short bridge_buffer_size; 31 | unsigned short mmap_buffer_size; 32 | } audio_init_status_t; 33 | 34 | typedef struct { 35 | unsigned short dsp_cmd; 36 | unsigned short dsp_audio_fmt; 37 | unsigned short sample_rate; 38 | unsigned short number_channels; 39 | unsigned short ds_stream_id; 40 | unsigned short stream_priority; 41 | } audio_params_data_t; 42 | 43 | typedef struct { 44 | unsigned short dsp_cmd; //DSP_CMD_SET_SPEECH_PARAMS 45 | unsigned short audio_fmt; //S16_LE,ALAW,ULAW,ILBC 46 | unsigned short sample_rate; 47 | unsigned short ds_stream_id; //Stream ID from EAP mixer 48 | unsigned short stream_priority; //N/A 49 | unsigned short frame_size; 50 | } speech_params_data_t; 51 | 52 | typedef struct { 53 | unsigned short dsp_cmd; 54 | unsigned short stream_id; 55 | unsigned short ds_stream_id; 56 | unsigned short bridge_buffer_size; 57 | unsigned short mmap_buffer_size; 58 | unsigned short status; 59 | unsigned int num_frames; 60 | unsigned short sample_rate; 61 | unsigned short number_channels; 62 | unsigned short vol_scale; 63 | unsigned short vol_power2; 64 | unsigned short left_gain; 65 | unsigned short right_gain; 66 | unsigned short dsp_audio_fmt; 67 | #ifndef NORMAL_DSP_TASK 68 | unsigned short mute; 69 | unsigned long int samples_played_high; 70 | unsigned long int samples_played_low; 71 | #endif 72 | } audio_status_info_t; 73 | 74 | typedef struct { 75 | unsigned short int dsp_cmd; 76 | unsigned short int status; 77 | } dsp_cmd_status_t; 78 | 79 | /* data write status structure */ 80 | typedef struct { 81 | unsigned short int dsp_cmd; 82 | unsigned short int status; 83 | unsigned short int buffer_bytes_free; 84 | } write_status_t; 85 | 86 | typedef struct { 87 | unsigned short dsp_cmd; 88 | unsigned short data_size; 89 | } data_write_t; 90 | 91 | typedef struct { 92 | unsigned short int dsp_cmd; 93 | unsigned short int status; 94 | unsigned short int frame_size; 95 | unsigned int stream_time_ms; 96 | } read_status_t; 97 | 98 | /* get time data structure */ 99 | typedef struct { 100 | unsigned short int dsp_cmd; 101 | unsigned short int status; 102 | unsigned short int stream_ID; 103 | long int time_ms; 104 | } time_data_t; 105 | 106 | /* general stream command data structure */ 107 | typedef struct { 108 | unsigned short int dsp_cmd; 109 | unsigned short int stream_ID; 110 | } stream_cmd_data_t; 111 | 112 | typedef struct { 113 | unsigned short dsp_cmd; 114 | unsigned short scale; 115 | unsigned short power2; 116 | } volume_data_t; 117 | 118 | typedef struct { 119 | unsigned short dsp_cmd; 120 | unsigned short left_gain; 121 | unsigned short right_gain; 122 | unsigned short steps; 123 | } panning_data_t; 124 | 125 | #endif /* _TYPES_H */ 126 | -------------------------------------------------------------------------------- /mix/60-upmix.conf: -------------------------------------------------------------------------------- 1 | pcm.upmix { 2 | @args [ SLAVE CHANNELS DELAY ] 3 | @args.SLAVE { 4 | type string 5 | default "plug:hw" 6 | } 7 | @args.CHANNELS { 8 | type integer 9 | default 6 10 | } 11 | @args.DELAY { 12 | type integer 13 | default 0 14 | } 15 | type upmix 16 | channels $CHANNELS 17 | delay $DELAY 18 | slave.pcm $SLAVE 19 | hint { 20 | show { 21 | @func refer 22 | name defaults.namehint.basic 23 | } 24 | description "Plugin for channel upmix (4,6,8)" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mix/60-vdownmix.conf: -------------------------------------------------------------------------------- 1 | pcm.vdownmix { 2 | @args [ SLAVE CHANNELS DELAY ] 3 | @args.SLAVE { 4 | type string 5 | default "plug:hw" 6 | } 7 | @args.CHANNELS { 8 | type integer 9 | default 6 10 | } 11 | @args.DELAY { 12 | type integer 13 | default 0 14 | } 15 | type vdownmix 16 | slave.pcm $SLAVE 17 | hint { 18 | show { 19 | @func refer 20 | name defaults.namehint.basic 21 | } 22 | description "Plugin for channel downmix (stereo) with a simple spacialization" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /mix/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 60-upmix.conf 60-vdownmix.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_upmix_LTLIBRARIES = libasound_module_pcm_upmix.la 6 | asound_module_pcm_vdownmix_LTLIBRARIES = libasound_module_pcm_vdownmix.la 7 | asound_module_gconf_DATA = $(GCONF_FILES) 8 | 9 | asound_module_pcm_upmixdir = @ALSA_PLUGIN_DIR@ 10 | asound_module_pcm_vdownmixdir = @ALSA_PLUGIN_DIR@ 11 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 12 | 13 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ 14 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 15 | 16 | libasound_module_pcm_upmix_la_SOURCES = pcm_upmix.c 17 | libasound_module_pcm_upmix_la_LIBADD = @ALSA_LIBS@ 18 | libasound_module_pcm_vdownmix_la_SOURCES = pcm_vdownmix.c 19 | libasound_module_pcm_vdownmix_la_LIBADD = @ALSA_LIBS@ 20 | 21 | include ../install-hooks.am 22 | 23 | install-data-hook: install-conf-hook 24 | 25 | uninstall-local: uninstall-conf-hook 26 | -------------------------------------------------------------------------------- /mix/pcm_vdownmix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 4/5/6 -> 2 downmix with a simple spacialization 3 | * 4 | * Copyright (c) 2006 by Takashi Iwai 5 | * 6 | * This library is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | /* #define I_AM_POWERFUL */ 25 | 26 | #ifdef I_AM_POWERFUL 27 | #define RINGBUF_SIZE (1 << 9) 28 | #else 29 | #define RINGBUF_SIZE (1 << 7) 30 | #endif 31 | #define RINGBUF_MASK (RINGBUF_SIZE - 1) 32 | 33 | struct vdownmix_tap { 34 | int delay; 35 | int weight; 36 | }; 37 | 38 | #define MAX_TAPS 30 39 | 40 | struct vdownmix_filter { 41 | int taps; 42 | struct vdownmix_tap tap[MAX_TAPS]; 43 | }; 44 | 45 | typedef struct { 46 | snd_pcm_extplug_t ext; 47 | int channels; 48 | unsigned int curpos; 49 | short rbuf[RINGBUF_SIZE][5]; 50 | } snd_pcm_vdownmix_t; 51 | 52 | static const struct vdownmix_filter tap_filters[5] = { 53 | { 54 | #ifdef I_AM_POWERFUL 55 | 18, 56 | #else 57 | 14, 58 | #endif 59 | {{ 0, 0xfffffd0a }, 60 | { 1, 0x41d }, 61 | { 2, 0xffffe657 }, 62 | { 3, 0x6eb5 }, 63 | { 4, 0xffffe657 }, 64 | { 5, 0x41d }, 65 | { 6, 0xfffffd0a }, 66 | { 71, 0xffffff1c }, 67 | { 72, 0x12e }, 68 | { 73, 0xfffff81a }, 69 | { 74, 0x24de }, 70 | { 75, 0xfffff81a }, 71 | { 76, 0x12e }, 72 | { 77, 0xffffff1c }, 73 | { 265, 0xfffffc65 }, 74 | { 266, 0xee1 }, 75 | { 267, 0xfffffc65 }, 76 | { 395, 0x46a }}, 77 | }, 78 | 79 | { 80 | #ifdef I_AM_POWERFUL 81 | 17, 82 | #else 83 | 10, 84 | #endif 85 | {{ 8, 0xcf }, 86 | { 9, 0xa7b }, 87 | { 10, 0xcd7 }, 88 | { 11, 0x5b3 }, 89 | { 12, 0x859 }, 90 | { 13, 0xaf }, 91 | { 80, 0x38b }, 92 | { 81, 0x454 }, 93 | { 82, 0x218 }, 94 | { 83, 0x2c1 }, 95 | { 268, 0x58b }, 96 | { 275, 0xc2 }, 97 | { 397, 0xbd }, 98 | { 398, 0x1e8 }, 99 | { 506, 0xfffffeac }, 100 | { 507, 0x636 }, 101 | { 508, 0xfffffeac }}, 102 | }, 103 | 104 | { 105 | #ifdef I_AM_POWERFUL 106 | 11, 107 | #else 108 | 1, 109 | #endif 110 | {{ 3, 0x4000 }, 111 | { 125, 0x12a }, 112 | { 126, 0xda1 }, 113 | { 127, 0x12a }, 114 | { 193, 0xfffffed3 }, 115 | { 194, 0xdb9 }, 116 | { 195, 0xfffffed3 }, 117 | { 454, 0x10a }, 118 | { 483, 0xfffffe97 }, 119 | { 484, 0x698 }, 120 | { 485, 0xfffffe97 }}, 121 | }, 122 | 123 | { 124 | #ifdef I_AM_POWERFUL 125 | 25, 126 | #else 127 | 10, 128 | #endif 129 | {{ 5, 0x1cb }, 130 | { 6, 0x9c5 }, 131 | { 7, 0x117e }, 132 | { 8, 0x200 }, 133 | { 9, 0x533 }, 134 | { 10, 0x1c6 }, 135 | { 11, 0x167 }, 136 | { 12, 0x5ff }, 137 | { 13, 0x425 }, 138 | { 14, 0xd9 }, 139 | { 128, 0x247 }, 140 | { 129, 0x5e1 }, 141 | { 130, 0xb7 }, 142 | { 131, 0x122 }, 143 | { 135, 0x10a }, 144 | { 200, 0x1b6 }, 145 | { 201, 0xa7 }, 146 | { 202, 0x188 }, 147 | { 203, 0x1d9 }, 148 | { 445, 0xffffff44 }, 149 | { 446, 0x5e2 }, 150 | { 447, 0xffffff44 }, 151 | { 484, 0xffffff51 }, 152 | { 485, 0x449 }, 153 | { 486, 0xffffff51 }}, 154 | }, 155 | 156 | { 157 | #ifdef I_AM_POWERFUL 158 | 21, 159 | #else 160 | 7, 161 | #endif 162 | {{ 0, 0xfffffdee }, 163 | { 1, 0x28b }, 164 | { 2, 0xffffed1e }, 165 | { 3, 0x6336 }, 166 | { 4, 0xffffed1e }, 167 | { 5, 0x28b }, 168 | { 6, 0xfffffdee }, 169 | { 51, 0xffffff2c }, 170 | { 52, 0x105 }, 171 | { 53, 0xfffff86b }, 172 | { 54, 0x27d9 }, 173 | { 55, 0xfffff86b }, 174 | { 56, 0x105 }, 175 | { 57, 0xffffff2c }, 176 | { 333, 0xfffffd69 }, 177 | { 334, 0xb2f }, 178 | { 335, 0xfffffd69 }, 179 | { 339, 0xdf }, 180 | { 340, 0x168 }, 181 | { 342, 0xa6 }, 182 | { 343, 0xba }}, 183 | }, 184 | }; 185 | 186 | static const int tap_index[5][2] = { 187 | /* left */ 188 | { 0, 1 }, 189 | /* right */ 190 | { 1, 0 }, 191 | /* rear left */ 192 | { 2, 3 }, 193 | /* rear right */ 194 | { 3, 2 }, 195 | /* center */ 196 | { 4, 4 }, 197 | }; 198 | 199 | static inline void *area_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) 200 | { 201 | unsigned int bitofs = area->first + area->step * offset; 202 | return (char *) area->addr + bitofs / 8; 203 | } 204 | 205 | static inline unsigned int area_step(const snd_pcm_channel_area_t *area) 206 | { 207 | return area->step / 8; 208 | } 209 | 210 | static snd_pcm_sframes_t 211 | vdownmix_transfer(snd_pcm_extplug_t *ext, 212 | const snd_pcm_channel_area_t *dst_areas, 213 | snd_pcm_uframes_t dst_offset, 214 | const snd_pcm_channel_area_t *src_areas, 215 | snd_pcm_uframes_t src_offset, 216 | snd_pcm_uframes_t size) 217 | { 218 | snd_pcm_vdownmix_t *mix = (snd_pcm_vdownmix_t *)ext; 219 | short *src[mix->channels], *ptr[2]; 220 | unsigned int src_step[mix->channels], step[2]; 221 | int i, ch, curpos, p, idx; 222 | int acc[2]; 223 | int fr; 224 | 225 | ptr[0] = area_addr(dst_areas, dst_offset); 226 | step[0] = area_step(dst_areas) / 2; 227 | ptr[1] = area_addr(dst_areas + 1, dst_offset); 228 | step[1] = area_step(dst_areas + 1) / 2; 229 | for (ch = 0; ch < mix->channels; ch++) { 230 | const snd_pcm_channel_area_t *src_area = &src_areas[ch]; 231 | src[ch] = area_addr(src_area, src_offset); 232 | src_step[ch] = area_step(src_area) / 2; 233 | } 234 | curpos = mix->curpos; 235 | fr = size; 236 | while (fr--) { 237 | acc[0] = acc[1] = 0; 238 | for (ch = 0; ch < mix->channels; ch++) { 239 | mix->rbuf[curpos][ch] = *src[ch]; 240 | for (idx = 0; idx < 2; idx++) { 241 | int f = tap_index[ch][idx]; 242 | const struct vdownmix_filter *filter; 243 | filter = &tap_filters[f]; 244 | for (i = 0; i < filter->taps; i++) { 245 | p = (curpos + RINGBUF_SIZE - filter->tap[i].delay) 246 | & RINGBUF_MASK; 247 | acc[idx] += mix->rbuf[p][ch] * filter->tap[i].weight; 248 | } 249 | } 250 | src[ch] += src_step[ch]; 251 | } 252 | for (idx = 0; idx < 2; idx++) { 253 | acc[idx] >>= 14; 254 | if (acc[idx] < -32768) 255 | *ptr[idx] = -32768; 256 | else if (acc[idx] > 32767) 257 | *ptr[idx] = 32767; 258 | else 259 | *ptr[idx] = acc[idx]; 260 | ptr[idx] += step[idx]; 261 | } 262 | curpos = (curpos + 1) & RINGBUF_MASK; 263 | } 264 | mix->curpos = curpos; 265 | return size; 266 | } 267 | 268 | 269 | static int vdownmix_init(snd_pcm_extplug_t *ext) 270 | { 271 | snd_pcm_vdownmix_t *mix = (snd_pcm_vdownmix_t *)ext; 272 | mix->channels = ext->channels; 273 | if (mix->channels > 5) /* ignore LFE */ 274 | mix->channels = 5; 275 | mix->curpos = 0; 276 | memset(mix->rbuf, 0, sizeof(mix->rbuf)); 277 | return 0; 278 | } 279 | 280 | #if SND_PCM_EXTPLUG_VERSION >= 0x10002 281 | static unsigned int chmap[6] = { 282 | SND_CHMAP_FL, SND_CHMAP_FR, 283 | SND_CHMAP_RL, SND_CHMAP_RR, 284 | SND_CHMAP_FC, SND_CHMAP_LFE, 285 | }; 286 | 287 | static snd_pcm_chmap_query_t **vdownmix_query_chmaps(snd_pcm_extplug_t *ext ATTRIBUTE_UNUSED) 288 | { 289 | snd_pcm_chmap_query_t **maps; 290 | int i; 291 | 292 | maps = calloc(4, sizeof(void *)); 293 | if (!maps) 294 | return NULL; 295 | for (i = 0; i < 3; i++) { 296 | snd_pcm_chmap_query_t *p; 297 | p = maps[i] = calloc(i + 4 + 2, sizeof(int)); 298 | if (!p) { 299 | snd_pcm_free_chmaps(maps); 300 | return NULL; 301 | } 302 | p->type = SND_CHMAP_TYPE_FIXED; 303 | p->map.channels = i + 4; 304 | memcpy(p->map.pos, chmap, (i + 4) * sizeof(int)); 305 | } 306 | return maps; 307 | } 308 | 309 | static snd_pcm_chmap_t *vdownmix_get_chmap(snd_pcm_extplug_t *ext) 310 | { 311 | snd_pcm_chmap_t *map; 312 | 313 | if (ext->channels < 4 || ext->channels > 6) 314 | return NULL; 315 | map = malloc((ext->channels + 1) * sizeof(int)); 316 | if (!map) 317 | return NULL; 318 | map->channels = ext->channels; 319 | memcpy(map->pos, chmap, ext->channels * sizeof(int)); 320 | return map; 321 | } 322 | #endif /* SND_PCM_EXTPLUG_VERSION >= 0x10002 */ 323 | 324 | static const snd_pcm_extplug_callback_t vdownmix_callback = { 325 | .transfer = vdownmix_transfer, 326 | .init = vdownmix_init, 327 | /* .dump = filr_dump, */ 328 | #if SND_PCM_EXTPLUG_VERSION >= 0x10002 329 | .query_chmaps = vdownmix_query_chmaps, 330 | .get_chmap = vdownmix_get_chmap, 331 | #endif 332 | }; 333 | 334 | SND_PCM_PLUGIN_DEFINE_FUNC(vdownmix) 335 | { 336 | snd_config_iterator_t i, next; 337 | snd_pcm_vdownmix_t *mix; 338 | snd_config_t *sconf = NULL; 339 | int err; 340 | 341 | snd_config_for_each(i, next, conf) { 342 | snd_config_t *n = snd_config_iterator_entry(i); 343 | const char *id; 344 | if (snd_config_get_id(n, &id) < 0) 345 | continue; 346 | if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) 347 | continue; 348 | if (strcmp(id, "slave") == 0) { 349 | sconf = n; 350 | continue; 351 | } 352 | SNDERR("Unknown field %s", id); 353 | return -EINVAL; 354 | } 355 | 356 | if (! sconf) { 357 | SNDERR("No slave configuration for vdownmix pcm"); 358 | return -EINVAL; 359 | } 360 | 361 | mix = calloc(1, sizeof(*mix)); 362 | if (mix == NULL) 363 | return -ENOMEM; 364 | 365 | mix->ext.version = SND_PCM_EXTPLUG_VERSION; 366 | mix->ext.name = "Vdownmix Plugin"; 367 | mix->ext.callback = &vdownmix_callback; 368 | mix->ext.private_data = mix; 369 | 370 | err = snd_pcm_extplug_create(&mix->ext, name, root, sconf, stream, mode); 371 | if (err < 0) { 372 | free(mix); 373 | return err; 374 | } 375 | 376 | /* 4/5/6 -> 2 downmix */ 377 | snd_pcm_extplug_set_param_minmax(&mix->ext, SND_PCM_EXTPLUG_HW_CHANNELS, 378 | 4, 6); 379 | snd_pcm_extplug_set_slave_param(&mix->ext, SND_PCM_EXTPLUG_HW_CHANNELS, 2); 380 | snd_pcm_extplug_set_param(&mix->ext, SND_PCM_EXTPLUG_HW_FORMAT, 381 | SND_PCM_FORMAT_S16); 382 | snd_pcm_extplug_set_slave_param(&mix->ext, SND_PCM_EXTPLUG_HW_FORMAT, 383 | SND_PCM_FORMAT_S16); 384 | 385 | *pcmp = mix->ext.pcm; 386 | return 0; 387 | } 388 | 389 | SND_PCM_PLUGIN_SYMBOL(vdownmix); 390 | -------------------------------------------------------------------------------- /oss/50-oss.conf: -------------------------------------------------------------------------------- 1 | pcm.oss { 2 | @args [ DEVICE ] 3 | @args.DEVICE { 4 | type string 5 | default "/dev/dsp" 6 | } 7 | type oss 8 | device $DEVICE 9 | hint { 10 | show { 11 | @func refer 12 | name defaults.namehint.basic 13 | } 14 | description "Open Sound System" 15 | } 16 | } 17 | 18 | ctl.oss { 19 | @args [ DEVICE ] 20 | @args.DEVICE { 21 | type string 22 | default "/dev/mixer" 23 | } 24 | type oss 25 | device $DEVICE 26 | } 27 | -------------------------------------------------------------------------------- /oss/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 50-oss.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_oss_LTLIBRARIES = libasound_module_pcm_oss.la 6 | asound_module_ctl_oss_LTLIBRARIES = libasound_module_ctl_oss.la 7 | asound_module_gconf_DATA = $(GCONF_FILES) 8 | 9 | asound_module_pcm_ossdir = @ALSA_PLUGIN_DIR@ 10 | asound_module_ctl_ossdir = @ALSA_PLUGIN_DIR@ 11 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 12 | 13 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ 14 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 15 | 16 | libasound_module_pcm_oss_la_SOURCES = pcm_oss.c 17 | libasound_module_pcm_oss_la_LIBADD = @ALSA_LIBS@ 18 | 19 | libasound_module_ctl_oss_la_SOURCES = ctl_oss.c 20 | libasound_module_ctl_oss_la_LIBADD = @ALSA_LIBS@ 21 | 22 | include ../install-hooks.am 23 | 24 | install-data-hook: install-conf-hook 25 | 26 | uninstall-local: uninstall-conf-hook 27 | -------------------------------------------------------------------------------- /oss/pcm_oss.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ALSA <-> OSS PCM I/O plugin 3 | * 4 | * Copyright (c) 2005 by Takashi Iwai 5 | * 6 | * This library is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "config.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #if defined(__linux__) 27 | #include 28 | #elif HAVE_SYS_SOUNDCARD_H 29 | #include 30 | #elif HAVE_SOUNDCARD_H 31 | #include 32 | #endif 33 | 34 | typedef struct snd_pcm_oss { 35 | snd_pcm_ioplug_t io; 36 | char *device; 37 | int fd; 38 | int fragment_set; 39 | int caps; 40 | int format; 41 | unsigned int period_shift; 42 | unsigned int periods; 43 | unsigned int frame_bytes; 44 | } snd_pcm_oss_t; 45 | 46 | static snd_pcm_sframes_t oss_write(snd_pcm_ioplug_t *io, 47 | const snd_pcm_channel_area_t *areas, 48 | snd_pcm_uframes_t offset, 49 | snd_pcm_uframes_t size) 50 | { 51 | snd_pcm_oss_t *oss = io->private_data; 52 | const char *buf; 53 | ssize_t result; 54 | 55 | /* we handle only an interleaved buffer */ 56 | buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; 57 | size *= oss->frame_bytes; 58 | result = write(oss->fd, buf, size); 59 | if (result <= 0) 60 | return result; 61 | return result / oss->frame_bytes; 62 | } 63 | 64 | static snd_pcm_sframes_t oss_read(snd_pcm_ioplug_t *io, 65 | const snd_pcm_channel_area_t *areas, 66 | snd_pcm_uframes_t offset, 67 | snd_pcm_uframes_t size) 68 | { 69 | snd_pcm_oss_t *oss = io->private_data; 70 | char *buf; 71 | ssize_t result; 72 | 73 | /* we handle only an interleaved buffer */ 74 | buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8; 75 | size *= oss->frame_bytes; 76 | result = read(oss->fd, buf, size); 77 | if (result <= 0) 78 | return result; 79 | return result / oss->frame_bytes; 80 | } 81 | 82 | static snd_pcm_sframes_t oss_pointer(snd_pcm_ioplug_t *io) 83 | { 84 | snd_pcm_oss_t *oss = io->private_data; 85 | struct count_info info; 86 | int ptr; 87 | 88 | if (ioctl(oss->fd, io->stream == SND_PCM_STREAM_PLAYBACK ? 89 | SNDCTL_DSP_GETOPTR : SNDCTL_DSP_GETIPTR, &info) < 0) { 90 | fprintf(stderr, "*** OSS: oss_pointer error\n"); 91 | return 0; 92 | } 93 | ptr = snd_pcm_bytes_to_frames(io->pcm, info.ptr); 94 | return ptr; 95 | } 96 | 97 | static int oss_start(snd_pcm_ioplug_t *io) 98 | { 99 | snd_pcm_oss_t *oss = io->private_data; 100 | int tmp = io->stream == SND_PCM_STREAM_PLAYBACK ? 101 | PCM_ENABLE_OUTPUT : PCM_ENABLE_INPUT; 102 | 103 | if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) { 104 | fprintf(stderr, "*** OSS: trigger failed\n"); 105 | if (io->stream == SND_PCM_STREAM_CAPTURE) 106 | /* fake read to trigger */ 107 | read(oss->fd, &tmp, 0); 108 | } 109 | return 0; 110 | } 111 | 112 | static int oss_stop(snd_pcm_ioplug_t *io) 113 | { 114 | snd_pcm_oss_t *oss = io->private_data; 115 | int tmp = 0; 116 | 117 | ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp); 118 | return 0; 119 | } 120 | 121 | static int oss_drain(snd_pcm_ioplug_t *io) 122 | { 123 | snd_pcm_oss_t *oss = io->private_data; 124 | 125 | if (io->stream == SND_PCM_STREAM_PLAYBACK) 126 | ioctl(oss->fd, SNDCTL_DSP_SYNC); 127 | return 0; 128 | } 129 | 130 | static int oss_prepare(snd_pcm_ioplug_t *io) 131 | { 132 | snd_pcm_oss_t *oss = io->private_data; 133 | int tmp; 134 | 135 | ioctl(oss->fd, SNDCTL_DSP_RESET); 136 | 137 | tmp = io->channels; 138 | if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) { 139 | perror("SNDCTL_DSP_CHANNELS"); 140 | return -EINVAL; 141 | } 142 | tmp = oss->format; 143 | if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &tmp) < 0) { 144 | perror("SNDCTL_DSP_SETFMT"); 145 | return -EINVAL; 146 | } 147 | tmp = io->rate; 148 | if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &tmp) < 0 || 149 | tmp > io->rate * 1.01 || tmp < io->rate * 0.99) { 150 | perror("SNDCTL_DSP_SPEED"); 151 | return -EINVAL; 152 | } 153 | return 0; 154 | } 155 | 156 | static int oss_hw_params(snd_pcm_ioplug_t *io, 157 | snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) 158 | { 159 | snd_pcm_oss_t *oss = io->private_data; 160 | int i, tmp, err; 161 | unsigned int period_bytes; 162 | long oflags, flags; 163 | 164 | oss->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; 165 | switch (io->format) { 166 | case SND_PCM_FORMAT_U8: 167 | oss->format = AFMT_U8; 168 | break; 169 | case SND_PCM_FORMAT_S16_LE: 170 | oss->format = AFMT_S16_LE; 171 | break; 172 | case SND_PCM_FORMAT_S16_BE: 173 | oss->format = AFMT_S16_BE; 174 | break; 175 | default: 176 | fprintf(stderr, "*** OSS: unsupported format %s\n", snd_pcm_format_name(io->format)); 177 | return -EINVAL; 178 | } 179 | period_bytes = io->period_size * oss->frame_bytes; 180 | oss->period_shift = 0; 181 | for (i = 31; i >= 4; i--) { 182 | if (period_bytes & (1U << i)) { 183 | oss->period_shift = i; 184 | break; 185 | } 186 | } 187 | if (! oss->period_shift) { 188 | fprintf(stderr, "*** OSS: invalid period size %d\n", (int)io->period_size); 189 | return -EINVAL; 190 | } 191 | oss->periods = io->buffer_size / io->period_size; 192 | 193 | _retry: 194 | tmp = oss->period_shift | (oss->periods << 16); 195 | if (ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) { 196 | if (! oss->fragment_set) { 197 | perror("SNDCTL_DSP_SETFRAGMENT"); 198 | fprintf(stderr, "*** period shift = %d, periods = %d\n", oss->period_shift, oss->periods); 199 | return -EINVAL; 200 | } 201 | /* OSS has no proper way to reinitialize the fragments */ 202 | /* try to reopen the device */ 203 | close(oss->fd); 204 | oss->fd = open(oss->device, io->stream == SND_PCM_STREAM_PLAYBACK ? 205 | O_WRONLY : O_RDONLY); 206 | if (oss->fd < 0) { 207 | err = -errno; 208 | SNDERR("Cannot reopen the device %s", oss->device); 209 | return err; 210 | } 211 | io->poll_fd = oss->fd; 212 | io->poll_events = io->stream == SND_PCM_STREAM_PLAYBACK ? 213 | POLLOUT : POLLIN; 214 | snd_pcm_ioplug_reinit_status(io); 215 | oss->fragment_set = 0; 216 | goto _retry; 217 | } 218 | oss->fragment_set = 1; 219 | 220 | if ((flags = fcntl(oss->fd, F_GETFL)) < 0) { 221 | err = -errno; 222 | perror("F_GETFL"); 223 | } else { 224 | oflags = flags; 225 | if (io->nonblock) 226 | flags |= O_NONBLOCK; 227 | else 228 | flags &= ~O_NONBLOCK; 229 | if (flags != oflags && 230 | fcntl(oss->fd, F_SETFL, flags) < 0) { 231 | err = -errno; 232 | perror("F_SETFL"); 233 | } 234 | } 235 | 236 | return 0; 237 | } 238 | 239 | #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) 240 | 241 | static int oss_hw_constraint(snd_pcm_oss_t *oss) 242 | { 243 | snd_pcm_ioplug_t *io = &oss->io; 244 | static const snd_pcm_access_t access_list[] = { 245 | SND_PCM_ACCESS_RW_INTERLEAVED, 246 | SND_PCM_ACCESS_MMAP_INTERLEAVED 247 | }; 248 | unsigned int nformats; 249 | unsigned int format[5]; 250 | unsigned int nchannels; 251 | unsigned int channel[6]; 252 | /* period and buffer bytes must be power of two */ 253 | static const unsigned int bytes_list[] = { 254 | 1U<<8, 1U<<9, 1U<<10, 1U<<11, 1U<<12, 1U<<13, 1U<<14, 1U<<15, 255 | 1U<<16, 1U<<17, 1U<<18, 1U<<19, 1U<<20, 1U<<21, 1U<<22, 1U<<23 256 | }; 257 | int i, err, tmp; 258 | 259 | /* check trigger */ 260 | oss->caps = 0; 261 | if (ioctl(oss->fd, SNDCTL_DSP_GETCAPS, &oss->caps) >= 0) { 262 | if (! (oss->caps & DSP_CAP_TRIGGER)) 263 | fprintf(stderr, "*** OSS: trigger is not supported!\n"); 264 | } 265 | 266 | /* access type - interleaved only */ 267 | if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, 268 | ARRAY_SIZE(access_list), access_list)) < 0) 269 | return err; 270 | 271 | /* supported formats */ 272 | tmp = 0; 273 | ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &tmp); 274 | nformats = 0; 275 | if (tmp & AFMT_U8) 276 | format[nformats++] = SND_PCM_FORMAT_U8; 277 | if (tmp & AFMT_S16_LE) 278 | format[nformats++] = SND_PCM_FORMAT_S16_LE; 279 | if (tmp & AFMT_S16_BE) 280 | format[nformats++] = SND_PCM_FORMAT_S16_BE; 281 | if (tmp & AFMT_MU_LAW) 282 | format[nformats++] = SND_PCM_FORMAT_MU_LAW; 283 | if (! nformats) 284 | format[nformats++] = SND_PCM_FORMAT_S16; 285 | if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, 286 | nformats, format)) < 0) 287 | return err; 288 | 289 | /* supported channels */ 290 | nchannels = 0; 291 | for (i = 0; i < 6; i++) { 292 | tmp = i + 1; 293 | if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) >= 0) 294 | channel[nchannels++] = tmp; 295 | } 296 | if (! nchannels) /* assume 2ch stereo */ 297 | err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 298 | 2, 2); 299 | else 300 | err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_CHANNELS, 301 | nchannels, channel); 302 | if (err < 0) 303 | return err; 304 | 305 | /* supported rates */ 306 | /* FIXME: should query? */ 307 | err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 480000); 308 | if (err < 0) 309 | return err; 310 | 311 | /* period size (in power of two) */ 312 | err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 313 | ARRAY_SIZE(bytes_list), bytes_list); 314 | if (err < 0) 315 | return err; 316 | /* periods */ 317 | err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 1024); 318 | if (err < 0) 319 | return err; 320 | /* buffer size (in power of two) */ 321 | err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES, 322 | ARRAY_SIZE(bytes_list), bytes_list); 323 | if (err < 0) 324 | return err; 325 | 326 | return 0; 327 | } 328 | 329 | 330 | static int oss_close(snd_pcm_ioplug_t *io) 331 | { 332 | snd_pcm_oss_t *oss = io->private_data; 333 | 334 | close(oss->fd); 335 | free(oss->device); 336 | free(oss); 337 | return 0; 338 | } 339 | 340 | static const snd_pcm_ioplug_callback_t oss_playback_callback = { 341 | .start = oss_start, 342 | .stop = oss_stop, 343 | .transfer = oss_write, 344 | .pointer = oss_pointer, 345 | .close = oss_close, 346 | .hw_params = oss_hw_params, 347 | .prepare = oss_prepare, 348 | .drain = oss_drain, 349 | }; 350 | 351 | static const snd_pcm_ioplug_callback_t oss_capture_callback = { 352 | .start = oss_start, 353 | .stop = oss_stop, 354 | .transfer = oss_read, 355 | .pointer = oss_pointer, 356 | .close = oss_close, 357 | .hw_params = oss_hw_params, 358 | .prepare = oss_prepare, 359 | .drain = oss_drain, 360 | }; 361 | 362 | 363 | SND_PCM_PLUGIN_DEFINE_FUNC(oss) 364 | { 365 | snd_config_iterator_t i, next; 366 | const char *device = "/dev/dsp"; 367 | int err; 368 | snd_pcm_oss_t *oss; 369 | 370 | snd_config_for_each(i, next, conf) { 371 | snd_config_t *n = snd_config_iterator_entry(i); 372 | const char *id; 373 | if (snd_config_get_id(n, &id) < 0) 374 | continue; 375 | if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) 376 | continue; 377 | if (strcmp(id, "device") == 0) { 378 | if (snd_config_get_string(n, &device) < 0) { 379 | SNDERR("Invalid type for %s", id); 380 | return -EINVAL; 381 | } 382 | continue; 383 | } 384 | SNDERR("Unknown field %s", id); 385 | return -EINVAL; 386 | } 387 | 388 | oss = calloc(1, sizeof(*oss)); 389 | if (! oss) { 390 | SNDERR("cannot allocate"); 391 | return -ENOMEM; 392 | } 393 | 394 | oss->device = strdup(device); 395 | if (oss->device == NULL) { 396 | SNDERR("cannot allocate"); 397 | free(oss); 398 | return -ENOMEM; 399 | } 400 | oss->fd = open(device, stream == SND_PCM_STREAM_PLAYBACK ? 401 | O_WRONLY : O_RDONLY); 402 | if (oss->fd < 0) { 403 | err = -errno; 404 | SNDERR("Cannot open device %s", device); 405 | goto error; 406 | } 407 | 408 | oss->io.version = SND_PCM_IOPLUG_VERSION; 409 | oss->io.name = "ALSA <-> OSS PCM I/O Plugin"; 410 | oss->io.poll_fd = oss->fd; 411 | oss->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; 412 | oss->io.mmap_rw = 0; 413 | oss->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? 414 | &oss_playback_callback : &oss_capture_callback; 415 | oss->io.private_data = oss; 416 | 417 | err = snd_pcm_ioplug_create(&oss->io, name, stream, mode); 418 | if (err < 0) 419 | goto error; 420 | 421 | if ((err = oss_hw_constraint(oss)) < 0) { 422 | snd_pcm_ioplug_delete(&oss->io); 423 | return err; 424 | } 425 | 426 | *pcmp = oss->io.pcm; 427 | return 0; 428 | 429 | error: 430 | if (oss->fd >= 0) 431 | close(oss->fd); 432 | free(oss->device); 433 | free(oss); 434 | return err; 435 | } 436 | 437 | SND_PCM_PLUGIN_SYMBOL(oss); 438 | -------------------------------------------------------------------------------- /pph/10-speexrate.conf: -------------------------------------------------------------------------------- 1 | pcm.speexrate { 2 | @args [ SLAVE RATE CONVERTER ] 3 | @args.SLAVE { 4 | type string 5 | default "plug:hw" 6 | } 7 | @args.RATE { 8 | type integer 9 | default 48000 10 | } 11 | @args.CONVERTER { 12 | type string 13 | default "speexrate" 14 | } 15 | type rate 16 | converter $CONVERTER 17 | slave { 18 | pcm $SLAVE 19 | rate $RATE 20 | } 21 | hint { 22 | show { 23 | @func refer 24 | name defaults.namehint.basic 25 | } 26 | description "Rate Converter Plugin Using Speex Resampler" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pph/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 10-speexrate.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_rate_speexrate_LTLIBRARIES = libasound_module_rate_speexrate.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_rate_speexratedir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -DVAR_ARRAYS -Wall -g @ALSA_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_rate_speexrate_la_SOURCES = rate_speexrate.c 15 | libasound_module_rate_speexrate_la_LIBADD = @ALSA_LIBS@ 16 | if USE_LIBSPEEX 17 | AM_CFLAGS += @speexdsp_CFLAGS@ 18 | libasound_module_rate_speexrate_la_LIBADD += @speexdsp_LIBS@ 19 | else 20 | AM_CFLAGS += -DRANDOM_PREFIX=alsa_lib -DOUTSIDE_SPEEX 21 | libasound_module_rate_speexrate_la_SOURCES += resample.c 22 | libasound_module_rate_speexrate_la_LIBADD += -lm 23 | endif 24 | 25 | noinst_HEADERS = speex_resampler.h arch.h fixed_generic.h 26 | 27 | include ../install-hooks.am 28 | 29 | install-exec-hook: 30 | rm -f $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_speexrate_*.so 31 | $(LN_S) libasound_module_rate_speexrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_speexrate_best.so 32 | $(LN_S) libasound_module_rate_speexrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_speexrate_medium.so 33 | 34 | uninstall-hook: 35 | rm -f $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_speexrate_*.so 36 | 37 | install-data-hook: install-conf-hook 38 | 39 | uninstall-local: uninstall-conf-hook 40 | -------------------------------------------------------------------------------- /pph/arch.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003 Jean-Marc Valin */ 2 | /** 3 | @file arch.h 4 | @brief Various architecture definitions Speex 5 | */ 6 | /* 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | - Neither the name of the Xiph.org Foundation nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef ARCH_H 36 | #define ARCH_H 37 | 38 | #ifndef OUTSIDE_SPEEX 39 | #include "speex/speexdsp_types.h" 40 | #endif 41 | 42 | #define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ 43 | #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ 44 | #define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 45 | #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 46 | #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ 47 | #define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 48 | #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 49 | 50 | #ifdef FIXED_POINT 51 | 52 | typedef spx_int16_t spx_word16_t; 53 | typedef spx_int32_t spx_word32_t; 54 | typedef spx_word32_t spx_mem_t; 55 | typedef spx_word16_t spx_coef_t; 56 | typedef spx_word16_t spx_lsp_t; 57 | typedef spx_word32_t spx_sig_t; 58 | 59 | #define Q15ONE 32767 60 | 61 | #define LPC_SCALING 8192 62 | #define SIG_SCALING 16384 63 | #define LSP_SCALING 8192. 64 | #define GAMMA_SCALING 32768. 65 | #define GAIN_SCALING 64 66 | #define GAIN_SCALING_1 0.015625 67 | 68 | #define LPC_SHIFT 13 69 | #define LSP_SHIFT 13 70 | #define SIG_SHIFT 14 71 | 72 | #define VERY_SMALL 0 73 | #define VERY_LARGE32 ((spx_word32_t)2147483647) 74 | #define VERY_LARGE16 ((spx_word16_t)32767) 75 | #define Q15_ONE ((spx_word16_t)32767) 76 | 77 | 78 | #ifdef FIXED_DEBUG 79 | #include "fixed_debug.h" 80 | #else 81 | 82 | #include "fixed_generic.h" 83 | 84 | #ifdef ARM5E_ASM 85 | #include "fixed_arm5e.h" 86 | #elif defined (ARM4_ASM) 87 | #include "fixed_arm4.h" 88 | #elif defined (ARM5E_ASM) 89 | #include "fixed_arm5e.h" 90 | #elif defined (BFIN_ASM) 91 | #include "fixed_bfin.h" 92 | #endif 93 | 94 | #endif 95 | 96 | 97 | #else 98 | 99 | typedef float spx_mem_t; 100 | typedef float spx_coef_t; 101 | typedef float spx_lsp_t; 102 | typedef float spx_sig_t; 103 | typedef float spx_word16_t; 104 | typedef float spx_word32_t; 105 | 106 | #define Q15ONE 1.0f 107 | #define LPC_SCALING 1.f 108 | #define SIG_SCALING 1.f 109 | #define LSP_SCALING 1.f 110 | #define GAMMA_SCALING 1.f 111 | #define GAIN_SCALING 1.f 112 | #define GAIN_SCALING_1 1.f 113 | 114 | #define LPC_SHIFT 0 115 | #define LSP_SHIFT 0 116 | #define SIG_SHIFT 0 117 | 118 | #define VERY_SMALL 1e-15f 119 | #define VERY_LARGE32 1e15f 120 | #define VERY_LARGE16 1e15f 121 | #define Q15_ONE ((spx_word16_t)1.f) 122 | 123 | #define QCONST16(x,bits) (x) 124 | #define QCONST32(x,bits) (x) 125 | 126 | #define NEG16(x) (-(x)) 127 | #define NEG32(x) (-(x)) 128 | #define EXTRACT16(x) (x) 129 | #define EXTEND32(x) (x) 130 | #define SHR16(a,shift) (a) 131 | #define SHL16(a,shift) (a) 132 | #define SHR32(a,shift) (a) 133 | #define SHL32(a,shift) (a) 134 | #define PSHR16(a,shift) (a) 135 | #define PSHR32(a,shift) (a) 136 | #define VSHR32(a,shift) (a) 137 | #define SATURATE16(x,a) (x) 138 | #define SATURATE32(x,a) (x) 139 | 140 | #define PSHR(a,shift) (a) 141 | #define SHR(a,shift) (a) 142 | #define SHL(a,shift) (a) 143 | #define SATURATE(x,a) (x) 144 | 145 | #define ADD16(a,b) ((a)+(b)) 146 | #define SUB16(a,b) ((a)-(b)) 147 | #define ADD32(a,b) ((a)+(b)) 148 | #define SUB32(a,b) ((a)-(b)) 149 | #define MULT16_16_16(a,b) ((a)*(b)) 150 | #define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) 151 | #define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) 152 | 153 | #define MULT16_32_Q11(a,b) ((a)*(b)) 154 | #define MULT16_32_Q13(a,b) ((a)*(b)) 155 | #define MULT16_32_Q14(a,b) ((a)*(b)) 156 | #define MULT16_32_Q15(a,b) ((a)*(b)) 157 | #define MULT16_32_P15(a,b) ((a)*(b)) 158 | 159 | #define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) 160 | #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) 161 | 162 | #define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) 163 | #define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) 164 | #define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) 165 | #define MULT16_16_Q11_32(a,b) ((a)*(b)) 166 | #define MULT16_16_Q13(a,b) ((a)*(b)) 167 | #define MULT16_16_Q14(a,b) ((a)*(b)) 168 | #define MULT16_16_Q15(a,b) ((a)*(b)) 169 | #define MULT16_16_P15(a,b) ((a)*(b)) 170 | #define MULT16_16_P13(a,b) ((a)*(b)) 171 | #define MULT16_16_P14(a,b) ((a)*(b)) 172 | 173 | #define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 174 | #define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 175 | #define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 176 | #define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 177 | 178 | 179 | #endif 180 | 181 | 182 | #if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) 183 | 184 | /* 2 on TI C5x DSP */ 185 | #define BYTES_PER_CHAR 2 186 | #define BITS_PER_CHAR 16 187 | #define LOG2_BITS_PER_CHAR 4 188 | 189 | #else 190 | 191 | #define BYTES_PER_CHAR 1 192 | #define BITS_PER_CHAR 8 193 | #define LOG2_BITS_PER_CHAR 3 194 | 195 | #endif 196 | 197 | #endif 198 | -------------------------------------------------------------------------------- /pph/fixed_generic.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003 Jean-Marc Valin */ 2 | /** 3 | @file fixed_generic.h 4 | @brief Generic fixed-point operations 5 | */ 6 | /* 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | - Neither the name of the Xiph.org Foundation nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef FIXED_GENERIC_H 36 | #define FIXED_GENERIC_H 37 | 38 | #define QCONST16(x,bits) ((spx_word16_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) 39 | #define QCONST32(x,bits) ((spx_word32_t)(.5+(x)*(((spx_word32_t)1)<<(bits)))) 40 | 41 | #define NEG16(x) (-(x)) 42 | #define NEG32(x) (-(x)) 43 | #define EXTRACT16(x) ((spx_word16_t)(x)) 44 | #define EXTEND32(x) ((spx_word32_t)(x)) 45 | #define SHR16(a,shift) ((a) >> (shift)) 46 | #define SHL16(a,shift) ((a) << (shift)) 47 | #define SHR32(a,shift) ((a) >> (shift)) 48 | #define SHL32(a,shift) ((a) << (shift)) 49 | #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) 50 | #define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) 51 | #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) 52 | #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 53 | #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 54 | 55 | #define SHR(a,shift) ((a) >> (shift)) 56 | #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) 57 | #define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) 58 | #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) 59 | 60 | 61 | #define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b))) 62 | #define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b)) 63 | #define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b)) 64 | #define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b)) 65 | 66 | 67 | /* result fits in 16 bits */ 68 | #define MULT16_16_16(a,b) ((((spx_word16_t)(a))*((spx_word16_t)(b)))) 69 | 70 | /* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */ 71 | #define MULT16_16(a,b) (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b))) 72 | 73 | #define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) 74 | #define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12)) 75 | #define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13)) 76 | #define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14)) 77 | 78 | #define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)) 79 | #define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))) 80 | 81 | #define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15)) 82 | #define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)) 83 | #define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) 84 | 85 | 86 | #define MAC16_16_Q11(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),11))) 87 | #define MAC16_16_Q13(c,a,b) (ADD32((c),SHR(MULT16_16((a),(b)),13))) 88 | #define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13))) 89 | 90 | #define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) 91 | #define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) 92 | #define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) 93 | #define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) 94 | 95 | #define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) 96 | #define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) 97 | #define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) 98 | 99 | #define MUL_16_32_R15(a,bh,bl) ADD32(MULT16_16((a),(bh)), SHR(MULT16_16((a),(bl)),15)) 100 | 101 | #define DIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a))/((spx_word16_t)(b)))) 102 | #define PDIV32_16(a,b) ((spx_word16_t)(((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word16_t)(b)))) 103 | #define DIV32(a,b) (((spx_word32_t)(a))/((spx_word32_t)(b))) 104 | #define PDIV32(a,b) (((spx_word32_t)(a)+((spx_word16_t)(b)>>1))/((spx_word32_t)(b))) 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /pph/rate_speexrate.c: -------------------------------------------------------------------------------- 1 | /* Rate converter plugin using Public Parrot Hack 2 | Copyright (C) 2007 Jean-Marc Valin 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. The name of the author may not be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include "config.h" 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef USE_LIBSPEEX 37 | #include 38 | #else 39 | #include "speex_resampler.h" 40 | #endif 41 | 42 | struct rate_src { 43 | int quality; 44 | unsigned int channels; 45 | SpeexResamplerState *st; 46 | }; 47 | 48 | static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames) 49 | { 50 | spx_uint32_t num, den; 51 | struct rate_src *rate = obj; 52 | if (frames == 0) 53 | return 0; 54 | speex_resampler_get_ratio(rate->st, &num, &den); 55 | return (snd_pcm_uframes_t)((frames*num+(den>>1))/den); 56 | } 57 | 58 | static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames) 59 | { 60 | spx_uint32_t num, den; 61 | struct rate_src *rate = obj; 62 | if (frames == 0) 63 | return 0; 64 | speex_resampler_get_ratio(rate->st, &num, &den); 65 | return (snd_pcm_uframes_t)((frames*den+(num>>1))/num); 66 | } 67 | 68 | static void pcm_src_free(void *obj) 69 | { 70 | struct rate_src *rate = obj; 71 | if (rate->st) 72 | { 73 | speex_resampler_destroy(rate->st); 74 | rate->st = NULL; 75 | } 76 | } 77 | 78 | static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) 79 | { 80 | struct rate_src *rate = obj; 81 | int err; 82 | 83 | if (! rate->st || rate->channels != info->channels) { 84 | if (rate->st) 85 | speex_resampler_destroy(rate->st); 86 | rate->channels = info->channels; 87 | rate->st = speex_resampler_init_frac(rate->channels, info->in.period_size, info->out.period_size, info->in.rate, info->out.rate, rate->quality, &err); 88 | if (! rate->st) 89 | return -EINVAL; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) 96 | { 97 | struct rate_src *rate = obj; 98 | speex_resampler_set_rate_frac(rate->st, info->in.period_size, info->out.period_size, info->in.rate, info->out.rate); 99 | return 0; 100 | } 101 | 102 | static void pcm_src_reset(void *obj) 103 | { 104 | struct rate_src *rate = obj; 105 | speex_resampler_reset_mem(rate->st); 106 | } 107 | 108 | static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames, 109 | const int16_t *src, unsigned int src_frames) 110 | { 111 | struct rate_src *rate = obj; 112 | speex_resampler_process_interleaved_int(rate->st, src, &src_frames, dst, &dst_frames); 113 | } 114 | 115 | static void pcm_src_close(void *obj) 116 | { 117 | free(obj); 118 | } 119 | 120 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 121 | static int get_supported_rates(void *obj, unsigned int *rate_min, 122 | unsigned int *rate_max) 123 | { 124 | *rate_min = *rate_max = 0; /* both unlimited */ 125 | return 0; 126 | } 127 | 128 | static void dump(void *obj, snd_output_t *out) 129 | { 130 | snd_output_printf(out, "Converter: libspeex " 131 | #ifdef USE_LIBSPEEX 132 | "(external)" 133 | #else 134 | "(builtin)" 135 | #endif 136 | "\n"); 137 | } 138 | #endif 139 | 140 | static snd_pcm_rate_ops_t pcm_src_ops = { 141 | .close = pcm_src_close, 142 | .init = pcm_src_init, 143 | .free = pcm_src_free, 144 | .reset = pcm_src_reset, 145 | .adjust_pitch = pcm_src_adjust_pitch, 146 | .convert_s16 = pcm_src_convert_s16, 147 | .input_frames = input_frames, 148 | .output_frames = output_frames, 149 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 150 | .version = SND_PCM_RATE_PLUGIN_VERSION, 151 | .get_supported_rates = get_supported_rates, 152 | .dump = dump, 153 | #endif 154 | }; 155 | 156 | static int pcm_src_open(unsigned int version, void **objp, 157 | snd_pcm_rate_ops_t *ops, int quality) 158 | { 159 | struct rate_src *rate; 160 | 161 | #if SND_PCM_RATE_PLUGIN_VERSION < 0x010002 162 | if (version != SND_PCM_RATE_PLUGIN_VERSION) { 163 | fprintf(stderr, "Invalid rate plugin version %x\n", version); 164 | return -EINVAL; 165 | } 166 | #endif 167 | rate = calloc(1, sizeof(*rate)); 168 | if (! rate) 169 | return -ENOMEM; 170 | rate->quality = quality; 171 | 172 | *objp = rate; 173 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 174 | if (version == 0x010001) 175 | memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t)); 176 | else 177 | #endif 178 | *ops = pcm_src_ops; 179 | return 0; 180 | } 181 | 182 | int SND_PCM_RATE_PLUGIN_ENTRY(speexrate) (unsigned int version, void **objp, 183 | snd_pcm_rate_ops_t *ops) 184 | { 185 | return pcm_src_open(version, objp, ops, 3); 186 | } 187 | 188 | int SND_PCM_RATE_PLUGIN_ENTRY(speexrate_best) (unsigned int version, void **objp, 189 | snd_pcm_rate_ops_t *ops) 190 | { 191 | return pcm_src_open(version, objp, ops, 10); 192 | } 193 | 194 | int SND_PCM_RATE_PLUGIN_ENTRY(speexrate_medium) (unsigned int version, void **objp, 195 | snd_pcm_rate_ops_t *ops) 196 | { 197 | return pcm_src_open(version, objp, ops, 5); 198 | } 199 | -------------------------------------------------------------------------------- /pulse/50-pulseaudio.conf: -------------------------------------------------------------------------------- 1 | # Add a specific named PulseAudio pcm and ctl (typically useful for testing) 2 | 3 | pcm.pulse { 4 | @args [ DEVICE ] 5 | @args.DEVICE { 6 | type string 7 | default "" 8 | } 9 | type pulse 10 | device $DEVICE 11 | hint { 12 | show { 13 | @func refer 14 | name defaults.namehint.basic 15 | } 16 | description "PulseAudio Sound Server" 17 | } 18 | } 19 | 20 | ctl.pulse { 21 | @args [ DEVICE ] 22 | @args.DEVICE { 23 | type string 24 | default "" 25 | } 26 | type pulse 27 | device $DEVICE 28 | } 29 | -------------------------------------------------------------------------------- /pulse/99-pulseaudio-default.conf.example: -------------------------------------------------------------------------------- 1 | # Default to PulseAudio 2 | 3 | pcm.!default { 4 | type pulse 5 | hint { 6 | show on 7 | description "Default ALSA Output (currently PulseAudio Sound Server)" 8 | } 9 | } 10 | 11 | ctl.!default { 12 | type pulse 13 | } 14 | -------------------------------------------------------------------------------- /pulse/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 50-pulseaudio.conf 2 | LCONF_FILES = 99-pulseaudio-default.conf.example 3 | 4 | EXTRA_DIST = $(GCONF_FILES) $(LCONF_FILES) 5 | 6 | asound_module_pcm_LTLIBRARIES = libasound_module_pcm_pulse.la 7 | asound_module_ctl_LTLIBRARIES = libasound_module_ctl_pulse.la 8 | asound_module_conf_LTLIBRARIES = libasound_module_conf_pulse.la 9 | asound_module_gconf_DATA = $(GCONF_FILES) 10 | asound_module_lconf_DATA = $(LCONF_FILES) 11 | 12 | asound_module_pcmdir = @ALSA_PLUGIN_DIR@ 13 | asound_module_ctldir = @ALSA_PLUGIN_DIR@ 14 | asound_module_confdir = @ALSA_PLUGIN_DIR@ 15 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 16 | asound_module_lconfdir = @ALSA_LCONF_DIR@ 17 | 18 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ $(PTHREAD_CFLAGS) $(pulseaudio_CFLAGS) -D_GNU_SOURCE 19 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 20 | 21 | libasound_module_pcm_pulse_la_SOURCES = pcm_pulse.c pulse.c pulse.h 22 | libasound_module_pcm_pulse_la_LIBADD = @ALSA_LIBS@ $(PTHREAD_LIBS) $(pulseaudio_LIBS) 23 | 24 | libasound_module_ctl_pulse_la_SOURCES = ctl_pulse.c pulse.c pulse.h 25 | libasound_module_ctl_pulse_la_LIBADD = @ALSA_LIBS@ $(PTHREAD_LIBS) $(pulseaudio_LIBS) 26 | 27 | libasound_module_conf_pulse_la_SOURCES = conf_pulse.c 28 | libasound_module_conf_pulse_la_LIBADD = @ALSA_LIBS@ $(PTHREAD_LIBS) $(pulseaudio_LIBS) 29 | 30 | include ../install-hooks.am 31 | 32 | install-data-hook: install-conf-hook 33 | 34 | uninstall-local: uninstall-conf-hook 35 | -------------------------------------------------------------------------------- /pulse/conf_pulse.c: -------------------------------------------------------------------------------- 1 | /*-*- linux-c -*-*/ 2 | 3 | /* 4 | * ALSA configuration function extensions for pulse 5 | * 6 | * Copyright (c) 2008 by Sjoerd Simons 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation; either version 2.1 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free 20 | * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 21 | * 02111-1307 USA 22 | * 23 | */ 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | 31 | /* Not actually part of the alsa api.... */ 32 | extern int 33 | snd_config_hook_load(snd_config_t * root, snd_config_t * config, 34 | snd_config_t ** dst, snd_config_t * private_data); 35 | 36 | int 37 | conf_pulse_hook_load_if_running(snd_config_t * root, snd_config_t * config, 38 | snd_config_t ** dst, 39 | snd_config_t * private_data) 40 | { 41 | pa_mainloop *loop = NULL; 42 | pa_context *context = NULL; 43 | int ret = 0, err, state; 44 | 45 | *dst = NULL; 46 | 47 | /* Defined if we're called inside the pulsedaemon itself */ 48 | if (getenv("PULSE_INTERNAL") != NULL) 49 | goto out; 50 | 51 | loop = pa_mainloop_new(); 52 | if (loop == NULL) 53 | goto out; 54 | 55 | context = pa_context_new(pa_mainloop_get_api(loop), "Alsa hook"); 56 | if (context == NULL) 57 | goto out; 58 | 59 | err = pa_context_connect(context, NULL, 0, NULL); 60 | if (err < 0) 61 | goto out; 62 | 63 | do { 64 | err = pa_mainloop_iterate(loop, 1, NULL); 65 | if (err < 0) 66 | goto out; 67 | 68 | state = pa_context_get_state(context); 69 | } while (state < PA_CONTEXT_AUTHORIZING); 70 | 71 | if (state > PA_CONTEXT_READY) 72 | goto out; 73 | 74 | ret = snd_config_hook_load(root, config, dst, private_data); 75 | 76 | out: 77 | if (context != NULL) 78 | pa_context_unref(context); 79 | 80 | if (loop != NULL) 81 | pa_mainloop_free(loop); 82 | 83 | return ret; 84 | } 85 | 86 | SND_DLSYM_BUILD_VERSION(conf_pulse_hook_load_if_running, 87 | SND_CONFIG_DLSYM_VERSION_HOOK); 88 | -------------------------------------------------------------------------------- /pulse/pulse.c: -------------------------------------------------------------------------------- 1 | /*-*- linux-c -*-*/ 2 | 3 | /* 4 | * ALSA <-> PulseAudio plugins 5 | * 6 | * Copyright (c) 2006 by Pierre Ossman 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation; either version 2.1 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "pulse.h" 29 | 30 | int pulse_check_connection(snd_pulse_t * p) 31 | { 32 | pa_context_state_t state; 33 | 34 | assert(p); 35 | 36 | if (!p->context || !p->mainloop) 37 | return -EBADFD; 38 | 39 | state = pa_context_get_state(p->context); 40 | 41 | if (!PA_CONTEXT_IS_GOOD(state)) 42 | return -EIO; 43 | 44 | return 0; 45 | } 46 | 47 | void pulse_context_success_cb(pa_context * c, int success, void *userdata) 48 | { 49 | snd_pulse_t *p = userdata; 50 | 51 | assert(c); 52 | assert(p); 53 | 54 | pa_threaded_mainloop_signal(p->mainloop, 0); 55 | } 56 | 57 | int pulse_wait_operation(snd_pulse_t * p, pa_operation * o) 58 | { 59 | assert(p); 60 | assert(o); 61 | 62 | for (;;) { 63 | int err; 64 | 65 | err = pulse_check_connection(p); 66 | if (err < 0) 67 | return err; 68 | 69 | if (pa_operation_get_state(o) != PA_OPERATION_RUNNING) 70 | break; 71 | 72 | pa_threaded_mainloop_wait(p->mainloop); 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | static void context_state_cb(pa_context * c, void *userdata) 79 | { 80 | pa_context_state_t state; 81 | snd_pulse_t *p = userdata; 82 | assert(c); 83 | 84 | state = pa_context_get_state(c); 85 | 86 | /* When we get disconnected, tell the process */ 87 | if (!PA_CONTEXT_IS_GOOD(state)) 88 | pulse_poll_activate(p); 89 | 90 | switch (state) { 91 | case PA_CONTEXT_READY: 92 | case PA_CONTEXT_TERMINATED: 93 | case PA_CONTEXT_FAILED: 94 | pa_threaded_mainloop_signal(p->mainloop, 0); 95 | break; 96 | 97 | case PA_CONTEXT_UNCONNECTED: 98 | case PA_CONTEXT_CONNECTING: 99 | case PA_CONTEXT_AUTHORIZING: 100 | case PA_CONTEXT_SETTING_NAME: 101 | break; 102 | } 103 | } 104 | 105 | static int make_nonblock(int fd) { 106 | int fl; 107 | 108 | if ((fl = fcntl(fd, F_GETFL)) < 0) 109 | return fl; 110 | 111 | if (fl & O_NONBLOCK) 112 | return 0; 113 | 114 | return fcntl(fd, F_SETFL, fl | O_NONBLOCK); 115 | } 116 | 117 | static int make_close_on_exec(int fd) 118 | { 119 | return fcntl(fd, F_SETFD, FD_CLOEXEC); 120 | } 121 | 122 | snd_pulse_t *pulse_new(void) 123 | { 124 | snd_pulse_t *p; 125 | int fd[2] = { -1, -1 }; 126 | char proc[PATH_MAX], buf[PATH_MAX + 20]; 127 | 128 | p = calloc(1, sizeof(snd_pulse_t)); 129 | 130 | if (!p) 131 | return NULL; 132 | 133 | if (pipe(fd)) { 134 | free(p); 135 | return NULL; 136 | } 137 | 138 | p->main_fd = fd[0]; 139 | p->thread_fd = fd[1]; 140 | 141 | make_nonblock(p->main_fd); 142 | make_close_on_exec(p->main_fd); 143 | make_nonblock(p->thread_fd); 144 | make_close_on_exec(p->thread_fd); 145 | 146 | p->mainloop = pa_threaded_mainloop_new(); 147 | if (!p->mainloop) 148 | goto fail; 149 | 150 | if (pa_get_binary_name(proc, sizeof(proc))) 151 | snprintf(buf, sizeof(buf), "ALSA plug-in [%s]", 152 | pa_path_get_filename(proc)); 153 | else 154 | snprintf(buf, sizeof(buf), "ALSA plug-in"); 155 | buf[sizeof(buf)-1] = 0; 156 | 157 | p->context = 158 | pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), buf); 159 | 160 | if (!p->context) 161 | goto fail; 162 | 163 | pa_context_set_state_callback(p->context, context_state_cb, p); 164 | 165 | if (pa_threaded_mainloop_start(p->mainloop) < 0) 166 | goto fail; 167 | 168 | return p; 169 | 170 | fail: 171 | pulse_free(p); 172 | 173 | return NULL; 174 | } 175 | 176 | void pulse_free(snd_pulse_t * p) 177 | { 178 | if (p->mainloop) 179 | pa_threaded_mainloop_stop(p->mainloop); 180 | 181 | if (p->context) { 182 | pa_context_disconnect(p->context); 183 | pa_context_unref(p->context); 184 | } 185 | 186 | if (p->mainloop) 187 | pa_threaded_mainloop_free(p->mainloop); 188 | 189 | if (p->thread_fd >= 0) 190 | close(p->thread_fd); 191 | 192 | if (p->main_fd >= 0) 193 | close(p->main_fd); 194 | 195 | free(p); 196 | } 197 | 198 | int pulse_connect(snd_pulse_t * p, const char *server, int can_fallback) 199 | { 200 | int err; 201 | pa_context_flags_t flags; 202 | pa_context_state_t state; 203 | 204 | assert(p); 205 | 206 | if (can_fallback) 207 | flags = PA_CONTEXT_NOAUTOSPAWN; 208 | else 209 | flags = 0; 210 | 211 | if (!p->context || !p->mainloop) 212 | return -EBADFD; 213 | 214 | state = pa_context_get_state(p->context); 215 | if (state != PA_CONTEXT_UNCONNECTED) 216 | return -EBADFD; 217 | 218 | pa_threaded_mainloop_lock(p->mainloop); 219 | 220 | err = pa_context_connect(p->context, server, flags, NULL); 221 | if (err < 0) 222 | goto error; 223 | 224 | for (;;) { 225 | pa_context_state_t state = pa_context_get_state(p->context); 226 | 227 | if (!PA_CONTEXT_IS_GOOD(state)) 228 | goto error; 229 | 230 | if (state == PA_CONTEXT_READY) 231 | break; 232 | 233 | pa_threaded_mainloop_wait(p->mainloop); 234 | } 235 | 236 | pa_threaded_mainloop_unlock(p->mainloop); 237 | 238 | return 0; 239 | 240 | error: 241 | if (!can_fallback) 242 | SNDERR("PulseAudio: Unable to connect: %s\n", 243 | pa_strerror(pa_context_errno(p->context))); 244 | 245 | pa_threaded_mainloop_unlock(p->mainloop); 246 | 247 | return -ECONNREFUSED; 248 | } 249 | 250 | void pulse_poll_activate(snd_pulse_t * p) 251 | { 252 | static const char x = 'x'; 253 | assert(p); 254 | 255 | write(p->thread_fd, &x, 1); 256 | } 257 | 258 | void pulse_poll_deactivate(snd_pulse_t * p) 259 | { 260 | char buf[10]; 261 | 262 | assert(p); 263 | 264 | /* Drain the pipe */ 265 | while (read(p->main_fd, buf, sizeof(buf)) > 0); 266 | } 267 | -------------------------------------------------------------------------------- /pulse/pulse.h: -------------------------------------------------------------------------------- 1 | /*-*- linux-c -*-*/ 2 | 3 | /* 4 | * ALSA <-> PulseAudio plugins 5 | * 6 | * Copyright (c) 2006 by Pierre Ossman 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as 10 | * published by the Free Software Foundation; either version 2.1 of 11 | * the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | 27 | #ifndef EBADFD 28 | #define EBADFD EBADF 29 | #endif 30 | 31 | #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 32 | 33 | typedef struct snd_pulse { 34 | pa_threaded_mainloop *mainloop; 35 | pa_context *context; 36 | 37 | int thread_fd, main_fd; 38 | } snd_pulse_t; 39 | 40 | int pulse_check_connection(snd_pulse_t * p); 41 | 42 | void pulse_context_success_cb(pa_context * c, int success, void *userdata); 43 | 44 | int pulse_wait_operation(snd_pulse_t * p, pa_operation * o); 45 | 46 | snd_pulse_t *pulse_new(void); 47 | void pulse_free(snd_pulse_t * p); 48 | 49 | int pulse_connect(snd_pulse_t * p, const char *server, int can_fallback); 50 | 51 | void pulse_poll_activate(snd_pulse_t * p); 52 | void pulse_poll_deactivate(snd_pulse_t * p); 53 | -------------------------------------------------------------------------------- /rate-lav/10-rate-lav.conf: -------------------------------------------------------------------------------- 1 | pcm.lavrate { 2 | @args [ SLAVE RATE CONVERTER ] 3 | @args.SLAVE { 4 | type string 5 | default "plug:hw" 6 | } 7 | @args.RATE { 8 | type integer 9 | default 48000 10 | } 11 | @args.CONVERTER { 12 | type string 13 | default "lavrate" 14 | } 15 | type rate 16 | converter $CONVERTER 17 | slave { 18 | pcm $SLAVE 19 | rate $RATE 20 | } 21 | hint { 22 | show { 23 | @func refer 24 | name defaults.namehint.basic 25 | } 26 | description "Rate Converter Plugin Using Libav/FFmpeg Library" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rate-lav/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 10-rate-lav.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_rate_lavrate_LTLIBRARIES = libasound_module_rate_lavrate.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_rate_lavratedir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @LIBAV_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_rate_lavrate_la_SOURCES = rate_lavrate.c 15 | libasound_module_rate_lavrate_la_LIBADD = @ALSA_LIBS@ @LIBAV_LIBS@ @LIBAV_RESAMPLE_LIBS@ 16 | 17 | noinst_HEADERS = gcd.h 18 | 19 | include ../install-hooks.am 20 | 21 | install-exec-hook: 22 | rm -f $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_*.so 23 | $(LN_S) libasound_module_rate_lavrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_higher.so 24 | $(LN_S) libasound_module_rate_lavrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_high.so 25 | $(LN_S) libasound_module_rate_lavrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_fast.so 26 | $(LN_S) libasound_module_rate_lavrate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_faster.so 27 | 28 | uninstall-hook: 29 | rm -f $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_lavrate_*.so 30 | install-data-hook: install-conf-hook 31 | 32 | uninstall-local: uninstall-conf-hook 33 | -------------------------------------------------------------------------------- /rate-lav/gcd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Fast implementation of greatest common divisor using the binary algorithm. 3 | * Copyright (c) 2007 Nicholas Kain 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to 7 | * deal in the Software without restriction, including without limitation the 8 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 | * sell copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 | * IN THE SOFTWARE. 22 | */ 23 | 24 | /* computes gcd using binary algorithm */ 25 | static int gcd(int a, int b) 26 | { 27 | int s,d; 28 | 29 | if (!a || !b) 30 | return a | b; 31 | 32 | for (s=0; ((a|b)&1) == 0; ++s) { 33 | a >>= 1; 34 | b >>= 1; 35 | } 36 | 37 | while ((a&1) == 0) 38 | a >>= 1; 39 | 40 | do { 41 | while ((b&1) == 0) { 42 | b >>= 1; 43 | } 44 | if (a>= 1; 52 | } while (b); 53 | 54 | return a << s; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /rate-lav/rate_lavrate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Rate converter plugin using libswresample 3 | * Copyright (c) 2014 by Anton Khirnov 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /* some compatibility wrappers */ 29 | #ifndef AV_VERSION_INT 30 | #define AV_VERSION_INT(a, b, c) (((a) << 16) | ((b) << 8) | (c)) 31 | #endif 32 | #ifndef LIBAVUTIL_VERSION_INT 33 | #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ 34 | LIBAVUTIL_VERSION_MINOR, \ 35 | LIBAVUTIL_VERSION_MICRO) 36 | #endif 37 | 38 | #define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)) 39 | 40 | static unsigned int filter_size = 16; 41 | 42 | struct rate_src { 43 | SwrContext *avr; 44 | 45 | unsigned int in_rate; 46 | unsigned int out_rate; 47 | unsigned int channels; 48 | 49 | unsigned int version; 50 | }; 51 | 52 | static snd_pcm_uframes_t input_frames(void *obj ATTRIBUTE_UNUSED, 53 | snd_pcm_uframes_t frames) 54 | { 55 | return frames; 56 | } 57 | 58 | static snd_pcm_uframes_t output_frames(void *obj ATTRIBUTE_UNUSED, 59 | snd_pcm_uframes_t frames) 60 | { 61 | return frames; 62 | } 63 | 64 | static void pcm_src_free(void *obj) 65 | { 66 | struct rate_src *rate = obj; 67 | swr_free(&rate->avr); 68 | } 69 | 70 | static int to_av_format(snd_pcm_format_t f) 71 | { 72 | switch (f) { 73 | case SND_PCM_FORMAT_FLOAT: 74 | return AV_SAMPLE_FMT_FLT; 75 | case SND_PCM_FORMAT_U8: 76 | return AV_SAMPLE_FMT_U8; 77 | case SND_PCM_FORMAT_S16: 78 | return AV_SAMPLE_FMT_S16; 79 | case SND_PCM_FORMAT_S32: 80 | default: 81 | return AV_SAMPLE_FMT_S32; 82 | } 83 | } 84 | 85 | static int support_multi_format(struct rate_src *rate) 86 | { 87 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 88 | return rate->version >= 0x010003; 89 | #else 90 | return 0; 91 | #endif 92 | } 93 | 94 | static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) 95 | { 96 | struct rate_src *rate = obj; 97 | int fmt; 98 | 99 | if (!rate->avr || rate->channels != info->channels) { 100 | int ret; 101 | 102 | pcm_src_free(rate); 103 | rate->channels = info->channels; 104 | rate->in_rate = info->in.rate; 105 | rate->out_rate = info->out.rate; 106 | 107 | rate->avr = swr_alloc(); 108 | if (!rate->avr) 109 | return -ENOMEM; 110 | 111 | #if HAVE_CH_LAYOUT 112 | AVChannelLayout layout; 113 | av_channel_layout_default(&layout, rate->channels); 114 | av_opt_set_chlayout(rate->avr, "in_chlayout", &layout, 0); 115 | av_opt_set_chlayout(rate->avr, "out_chlayout", &layout, 0); 116 | #else 117 | av_opt_set_channel_layout(rate->avr, "in_channel_layout", 118 | av_get_default_channel_layout(rate->channels), 0); 119 | av_opt_set_channel_layout(rate->avr, "out_channel_layout", 120 | av_get_default_channel_layout(rate->channels), 0); 121 | #endif 122 | av_opt_set_int(rate->avr, "in_sample_rate", rate->in_rate, 0); 123 | av_opt_set_int(rate->avr, "out_sample_rate", rate->out_rate, 0); 124 | fmt = support_multi_format(rate) ? info->in.format : SND_PCM_FORMAT_S16; 125 | av_opt_set_sample_fmt(rate->avr, "in_sample_fmt", 126 | to_av_format(fmt), 0); 127 | fmt = support_multi_format(rate) ? info->out.format : SND_PCM_FORMAT_S16; 128 | av_opt_set_sample_fmt(rate->avr, "out_sample_fmt", 129 | to_av_format(fmt), 0); 130 | 131 | ret = swr_init(rate->avr); 132 | if (ret < 0) { 133 | SNDERR("sw_init() error %d\n", ret); 134 | swr_free(&rate->avr); 135 | return -EINVAL; 136 | } 137 | } 138 | 139 | return 0; 140 | } 141 | 142 | static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) 143 | { 144 | struct rate_src *rate = obj; 145 | 146 | if (info->out.rate != rate->out_rate || info->in.rate != rate->in_rate) 147 | pcm_src_init(obj, info); 148 | return 0; 149 | } 150 | 151 | static void pcm_src_reset(void *obj) 152 | { 153 | struct rate_src *rate = obj; 154 | 155 | if (rate->avr) { 156 | #if 0 157 | swr_free(rate->avr); 158 | swr_init(rate->avr); 159 | #endif 160 | } 161 | } 162 | 163 | static void do_convert(struct rate_src *rate, 164 | void *dst, unsigned int dst_frames, 165 | const void *src, unsigned int src_frames) 166 | { 167 | unsigned int total_in = swr_get_delay(rate->avr, rate->in_rate) + src_frames; 168 | 169 | swr_convert(rate->avr, (uint8_t **)&dst, dst_frames, 170 | (const uint8_t **)&src, src_frames); 171 | 172 | swr_set_compensation(rate->avr, 173 | total_in - src_frames > filter_size ? 0 : 1, 174 | src_frames); 175 | } 176 | 177 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 178 | static void pcm_src_convert(void *obj, 179 | const snd_pcm_channel_area_t *dst_areas, 180 | snd_pcm_uframes_t dst_offset, 181 | unsigned int dst_frames, 182 | const snd_pcm_channel_area_t *src_areas, 183 | snd_pcm_uframes_t src_offset, 184 | unsigned int src_frames) 185 | { 186 | struct rate_src *rate = obj; 187 | const void *src = snd_pcm_channel_area_addr(src_areas, src_offset); 188 | void *dst = snd_pcm_channel_area_addr(dst_areas, dst_offset); 189 | 190 | do_convert(rate, dst, dst_frames, src, src_frames); 191 | } 192 | #endif 193 | 194 | static void pcm_src_convert_s16(void *obj, int16_t *dst, 195 | unsigned int dst_frames, 196 | const int16_t *src, 197 | unsigned int src_frames) 198 | { 199 | struct rate_src *rate = obj; 200 | 201 | do_convert(rate, dst, dst_frames, src, src_frames); 202 | } 203 | 204 | static void pcm_src_close(void *obj) 205 | { 206 | pcm_src_free(obj); 207 | } 208 | 209 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 210 | static int get_supported_rates(void *obj ATTRIBUTE_UNUSED, 211 | unsigned int *rate_min, 212 | unsigned int *rate_max) 213 | { 214 | *rate_min = *rate_max = 0; /* both unlimited */ 215 | return 0; 216 | } 217 | 218 | static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out) 219 | { 220 | snd_output_printf(out, "Converter: libswresample\n"); 221 | } 222 | #endif 223 | 224 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 225 | static int get_supported_formats(void *obj, uint64_t *in_formats, 226 | uint64_t *out_formats, 227 | unsigned int *flags) 228 | { 229 | *in_formats = *out_formats = 230 | (1ULL << SND_PCM_FORMAT_U8) | 231 | (1ULL << SND_PCM_FORMAT_S16) | 232 | (1ULL << SND_PCM_FORMAT_S32); 233 | *flags = SND_PCM_RATE_FLAG_INTERLEAVED; 234 | return 0; 235 | } 236 | #endif 237 | 238 | static snd_pcm_rate_ops_t pcm_src_ops = { 239 | .close = pcm_src_close, 240 | .init = pcm_src_init, 241 | .free = pcm_src_free, 242 | .reset = pcm_src_reset, 243 | .adjust_pitch = pcm_src_adjust_pitch, 244 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 245 | .convert = pcm_src_convert, 246 | #endif 247 | .convert_s16 = pcm_src_convert_s16, 248 | .input_frames = input_frames, 249 | .output_frames = output_frames, 250 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 251 | .version = SND_PCM_RATE_PLUGIN_VERSION, 252 | .get_supported_rates = get_supported_rates, 253 | .dump = dump, 254 | #endif 255 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 256 | .get_supported_formats = get_supported_formats, 257 | #endif 258 | }; 259 | 260 | int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops) 261 | { 262 | struct rate_src *rate; 263 | 264 | rate = calloc(1, sizeof(*rate)); 265 | if (!rate) 266 | return -ENOMEM; 267 | 268 | *objp = rate; 269 | rate->avr = NULL; 270 | rate->version = version; 271 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 272 | if (version == 0x010001) { 273 | memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t)); 274 | return 0; 275 | } 276 | #endif 277 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 278 | if (version == 0x010002) { 279 | memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_v2_ops_t)); 280 | return 0; 281 | } 282 | #endif 283 | *ops = pcm_src_ops; 284 | return 0; 285 | } 286 | 287 | int SND_PCM_RATE_PLUGIN_ENTRY(lavrate)(unsigned int version, void **objp, 288 | snd_pcm_rate_ops_t *ops) 289 | { 290 | return pcm_src_open(version, objp, ops); 291 | } 292 | int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_higher)(unsigned int version, 293 | void **objp, snd_pcm_rate_ops_t *ops) 294 | { 295 | filter_size = 64; 296 | return pcm_src_open(version, objp, ops); 297 | } 298 | int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_high)(unsigned int version, 299 | void **objp, snd_pcm_rate_ops_t *ops) 300 | { 301 | filter_size = 32; 302 | return pcm_src_open(version, objp, ops); 303 | } 304 | int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_fast)(unsigned int version, 305 | void **objp, snd_pcm_rate_ops_t *ops) 306 | { 307 | filter_size = 8; 308 | return pcm_src_open(version, objp, ops); 309 | } 310 | int SND_PCM_RATE_PLUGIN_ENTRY(lavrate_faster)(unsigned int version, 311 | void **objp, snd_pcm_rate_ops_t *ops) 312 | { 313 | filter_size = 4; 314 | return pcm_src_open(version, objp, ops); 315 | } 316 | 317 | 318 | -------------------------------------------------------------------------------- /rate/10-samplerate.conf: -------------------------------------------------------------------------------- 1 | pcm.samplerate { 2 | @args [ SLAVE RATE CONVERTER ] 3 | @args.SLAVE { 4 | type string 5 | default "plug:hw" 6 | } 7 | @args.RATE { 8 | type integer 9 | default 48000 10 | } 11 | @args.CONVERTER { 12 | type string 13 | default "samplerate" 14 | } 15 | type rate 16 | converter $CONVERTER 17 | slave { 18 | pcm $SLAVE 19 | rate $RATE 20 | } 21 | hint { 22 | show { 23 | @func refer 24 | name defaults.namehint.basic 25 | } 26 | description "Rate Converter Plugin Using Samplerate Library" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rate/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 10-samplerate.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_rate_samplerate_LTLIBRARIES = libasound_module_rate_samplerate.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_rate_sampleratedir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ $(samplerate_CFLAGS) 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_rate_samplerate_la_SOURCES = rate_samplerate.c 15 | libasound_module_rate_samplerate_la_LIBADD = @ALSA_LIBS@ @samplerate_LIBS@ 16 | 17 | include ../install-hooks.am 18 | 19 | install-exec-hook: 20 | rm -f $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_samplerate_*.so 21 | $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_samplerate_best.so 22 | $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_samplerate_medium.so 23 | $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_samplerate_order.so 24 | $(LN_S) libasound_module_rate_samplerate.so $(DESTDIR)@ALSA_PLUGIN_DIR@/libasound_module_rate_samplerate_linear.so 25 | 26 | uninstall-hook: 27 | rm -f $(DESTDIR)$(libdir)/alsa-lib/libasound_module_rate_samplerate_*.so 28 | 29 | install-data-hook: install-conf-hook 30 | 31 | uninstall-local: uninstall-conf-hook 32 | -------------------------------------------------------------------------------- /rate/rate_samplerate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Rate converter plugin using libsamplerate 3 | * 4 | * Copyright (c) 2006 by Takashi Iwai 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | struct rate_src { 23 | unsigned int version; 24 | double ratio; 25 | int converter; 26 | unsigned int channels; 27 | int in_int; 28 | int out_int; 29 | float *src_buf; 30 | float *dst_buf; 31 | SRC_STATE *state; 32 | SRC_DATA data; 33 | }; 34 | 35 | static snd_pcm_uframes_t input_frames(void *obj, snd_pcm_uframes_t frames) 36 | { 37 | struct rate_src *rate = obj; 38 | if (frames == 0) 39 | return 0; 40 | return (snd_pcm_uframes_t)(frames / rate->ratio); 41 | } 42 | 43 | static snd_pcm_uframes_t output_frames(void *obj, snd_pcm_uframes_t frames) 44 | { 45 | struct rate_src *rate = obj; 46 | if (frames == 0) 47 | return 0; 48 | return (snd_pcm_uframes_t)(frames * rate->ratio); 49 | } 50 | 51 | static void pcm_src_free(void *obj) 52 | { 53 | struct rate_src *rate = obj; 54 | 55 | free(rate->src_buf); 56 | free(rate->dst_buf); 57 | rate->src_buf = rate->dst_buf = NULL; 58 | 59 | if (rate->state) { 60 | src_delete(rate->state); 61 | rate->state = NULL; 62 | } 63 | } 64 | 65 | static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) 66 | { 67 | struct rate_src *rate = obj; 68 | int err; 69 | 70 | if (! rate->state || rate->channels != info->channels) { 71 | if (rate->state) 72 | src_delete(rate->state); 73 | rate->channels = info->channels; 74 | rate->state = src_new(rate->converter, rate->channels, &err); 75 | if (! rate->state) 76 | return -EINVAL; 77 | } 78 | 79 | rate->ratio = (double)info->out.rate / (double)info->in.rate; 80 | 81 | free(rate->src_buf); 82 | rate->src_buf = malloc(sizeof(float) * rate->channels * info->in.period_size); 83 | free(rate->dst_buf); 84 | rate->dst_buf = malloc(sizeof(float) * rate->channels * info->out.period_size); 85 | if (! rate->src_buf || ! rate->dst_buf) { 86 | pcm_src_free(rate); 87 | return -ENOMEM; 88 | } 89 | 90 | rate->data.data_in = rate->src_buf; 91 | rate->data.data_out = rate->dst_buf; 92 | rate->data.src_ratio = rate->ratio; 93 | rate->data.end_of_input = 0; 94 | 95 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 96 | if (rate->version >= 0x010003) { 97 | rate->in_int = info->in.format == SND_PCM_FORMAT_S32; 98 | rate->out_int = info->out.format == SND_PCM_FORMAT_S32; 99 | } 100 | #endif 101 | 102 | return 0; 103 | } 104 | 105 | static int pcm_src_adjust_pitch(void *obj, snd_pcm_rate_info_t *info) 106 | { 107 | struct rate_src *rate = obj; 108 | 109 | rate->ratio = ((double)info->out.period_size / (double)info->in.period_size); 110 | rate->data.src_ratio = rate->ratio; 111 | return 0; 112 | } 113 | 114 | static void pcm_src_reset(void *obj) 115 | { 116 | struct rate_src *rate = obj; 117 | 118 | src_reset(rate->state); 119 | } 120 | 121 | static void do_convert(struct rate_src *rate, 122 | void *dst, unsigned int dst_frames, 123 | const void *src, unsigned int src_frames) 124 | { 125 | unsigned int ofs; 126 | 127 | rate->data.input_frames = src_frames; 128 | rate->data.output_frames = dst_frames; 129 | rate->data.end_of_input = 0; 130 | 131 | if (rate->in_int) 132 | src_int_to_float_array(src, rate->src_buf, src_frames * rate->channels); 133 | else 134 | src_short_to_float_array(src, rate->src_buf, src_frames * rate->channels); 135 | src_process(rate->state, &rate->data); 136 | if (rate->data.output_frames_gen < dst_frames) 137 | ofs = dst_frames - rate->data.output_frames_gen; 138 | else 139 | ofs = 0; 140 | if (rate->out_int) 141 | src_float_to_int_array(rate->dst_buf, dst + ofs * rate->channels * 4, 142 | rate->data.output_frames_gen * rate->channels); 143 | else 144 | src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels * 2, 145 | rate->data.output_frames_gen * rate->channels); 146 | } 147 | 148 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 149 | static void pcm_src_convert(void *obj, 150 | const snd_pcm_channel_area_t *dst_areas, 151 | snd_pcm_uframes_t dst_offset, 152 | unsigned int dst_frames, 153 | const snd_pcm_channel_area_t *src_areas, 154 | snd_pcm_uframes_t src_offset, 155 | unsigned int src_frames) 156 | { 157 | struct rate_src *rate = obj; 158 | const void *src = snd_pcm_channel_area_addr(src_areas, src_offset); 159 | void *dst = snd_pcm_channel_area_addr(dst_areas, dst_offset); 160 | 161 | do_convert(rate, dst, dst_frames, src, src_frames); 162 | } 163 | #endif 164 | 165 | static void pcm_src_convert_s16(void *obj, int16_t *dst, unsigned int dst_frames, 166 | const int16_t *src, unsigned int src_frames) 167 | { 168 | struct rate_src *rate = obj; 169 | 170 | do_convert(rate, dst, dst_frames, src, src_frames); 171 | } 172 | 173 | static void pcm_src_close(void *obj) 174 | { 175 | free(obj); 176 | } 177 | 178 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 179 | static int get_supported_rates(void *obj ATTRIBUTE_UNUSED, unsigned int *rate_min, 180 | unsigned int *rate_max) 181 | { 182 | *rate_min = *rate_max = 0; /* both unlimited */ 183 | return 0; 184 | } 185 | 186 | static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out) 187 | { 188 | snd_output_printf(out, "Converter: libsamplerate\n"); 189 | } 190 | #endif 191 | 192 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 193 | static int get_supported_formats(void *obj, uint64_t *in_formats, 194 | uint64_t *out_formats, 195 | unsigned int *flags) 196 | { 197 | *in_formats = *out_formats = 198 | (1ULL << SND_PCM_FORMAT_S16) | 199 | (1ULL << SND_PCM_FORMAT_S32); 200 | *flags = SND_PCM_RATE_FLAG_INTERLEAVED; 201 | return 0; 202 | } 203 | #endif 204 | 205 | static snd_pcm_rate_ops_t pcm_src_ops = { 206 | .close = pcm_src_close, 207 | .init = pcm_src_init, 208 | .free = pcm_src_free, 209 | .reset = pcm_src_reset, 210 | .adjust_pitch = pcm_src_adjust_pitch, 211 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 212 | .convert = pcm_src_convert, 213 | #endif 214 | .convert_s16 = pcm_src_convert_s16, 215 | .input_frames = input_frames, 216 | .output_frames = output_frames, 217 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 218 | .version = SND_PCM_RATE_PLUGIN_VERSION, 219 | .get_supported_rates = get_supported_rates, 220 | .dump = dump, 221 | #endif 222 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 223 | .get_supported_formats = get_supported_formats, 224 | #endif 225 | }; 226 | 227 | static int pcm_src_open(unsigned int version, void **objp, 228 | snd_pcm_rate_ops_t *ops, int type) 229 | { 230 | struct rate_src *rate; 231 | 232 | rate = calloc(1, sizeof(*rate)); 233 | if (! rate) 234 | return -ENOMEM; 235 | 236 | rate->version = version; 237 | rate->converter = type; 238 | 239 | *objp = rate; 240 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 241 | if (version == 0x010001) { 242 | memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t)); 243 | return 0; 244 | } 245 | #endif 246 | #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 247 | if (version == 0x010002) { 248 | memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_v2_ops_t)); 249 | return 0; 250 | } 251 | #endif 252 | *ops = pcm_src_ops; 253 | return 0; 254 | } 255 | 256 | int SND_PCM_RATE_PLUGIN_ENTRY(samplerate) (unsigned int version, void **objp, 257 | snd_pcm_rate_ops_t *ops) 258 | { 259 | return pcm_src_open(version, objp, ops, SRC_SINC_FASTEST); 260 | } 261 | 262 | int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_best) (unsigned int version, void **objp, 263 | snd_pcm_rate_ops_t *ops) 264 | { 265 | return pcm_src_open(version, objp, ops, SRC_SINC_BEST_QUALITY); 266 | } 267 | 268 | int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_medium) (unsigned int version, void **objp, 269 | snd_pcm_rate_ops_t *ops) 270 | { 271 | return pcm_src_open(version, objp, ops, SRC_SINC_MEDIUM_QUALITY); 272 | } 273 | 274 | int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_order) (unsigned int version, void **objp, 275 | snd_pcm_rate_ops_t *ops) 276 | { 277 | return pcm_src_open(version, objp, ops, SRC_ZERO_ORDER_HOLD); 278 | } 279 | 280 | int SND_PCM_RATE_PLUGIN_ENTRY(samplerate_linear) (unsigned int version, void **objp, 281 | snd_pcm_rate_ops_t *ops) 282 | { 283 | return pcm_src_open(version, objp, ops, SRC_LINEAR); 284 | } 285 | -------------------------------------------------------------------------------- /speex/60-speex.conf: -------------------------------------------------------------------------------- 1 | pcm.speex { 2 | @args [ SLAVE AGC AGC_LEVEL DENOISE ECHO 3 | DEREVERB DEREVERB_DECAY DEREVERB_LEVEL 4 | FRAMES FILTER_LENGTH ] 5 | @args.SLAVE { 6 | type string 7 | default "plug:hw" 8 | } 9 | @args.AGC { 10 | type string 11 | default off 12 | } 13 | @args.AGC_LEVEL { 14 | type integer 15 | default 8000 16 | } 17 | @args.DENOISE { 18 | type string 19 | default on 20 | } 21 | @args.ECHO { 22 | type string 23 | default off 24 | } 25 | @args.DEREVERB { 26 | type string 27 | default off 28 | } 29 | @args.DEREVERB_DECAY { 30 | type real 31 | default 0 32 | } 33 | @args.DEREVERB_LEVEL { 34 | type real 35 | default 0 36 | } 37 | @args.FRAMES { 38 | type integer 39 | default 64 40 | } 41 | @args.FILTER_LENGTH { 42 | type integer 43 | default 256 44 | } 45 | type speex 46 | agc $AGC 47 | agc_level $AGC_LEVEL 48 | denoise $DENOISE 49 | echo $ECHO 50 | dereverb $DEREVERB 51 | dereverb_decay $DEREVERB_DECAY 52 | dereverb_level $DEREVERB_LEVEL 53 | frames $FRAMES 54 | filter_length $FILTER_LENGTH 55 | slave.pcm $SLAVE 56 | hint { 57 | show { 58 | @func refer 59 | name defaults.namehint.basic 60 | } 61 | description "Plugin using Speex DSP (resample, agc, denoise, echo, dereverb)" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /speex/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 60-speex.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_speex_LTLIBRARIES = libasound_module_pcm_speex.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_pcm_speexdir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @speexdsp_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_pcm_speex_la_SOURCES = pcm_speex.c 15 | libasound_module_pcm_speex_la_LIBADD = @ALSA_LIBS@ @speexdsp_LIBS@ 16 | 17 | include ../install-hooks.am 18 | 19 | install-data-hook: install-conf-hook 20 | 21 | uninstall-local: uninstall-conf-hook 22 | -------------------------------------------------------------------------------- /speex/pcm_speex.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Speex DSP plugin 3 | * 4 | * Copyright (c) 2009 by Takashi Iwai 5 | * 6 | * This library is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #include "config.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /* DSP parameters */ 28 | struct spx_parms { 29 | int frames; 30 | int denoise; 31 | int agc; 32 | int echo; 33 | int filter_length; 34 | float agc_level; 35 | int dereverb; 36 | float dereverb_decay; 37 | float dereverb_level; 38 | }; 39 | 40 | typedef struct { 41 | snd_pcm_extplug_t ext; 42 | struct spx_parms parms; 43 | /* instance and intermedate buffer */ 44 | SpeexPreprocessState *state; 45 | SpeexEchoState *echo_state; 46 | short *buf; 47 | short *outbuf; 48 | /* running states */ 49 | unsigned int filled; 50 | unsigned int processed; 51 | } snd_pcm_speex_t; 52 | 53 | 54 | static inline void *area_addr(const snd_pcm_channel_area_t *area, 55 | snd_pcm_uframes_t offset) 56 | { 57 | unsigned int bitofs = area->first + area->step * offset; 58 | return (char *) area->addr + bitofs / 8; 59 | } 60 | 61 | static snd_pcm_sframes_t 62 | spx_transfer(snd_pcm_extplug_t *ext, 63 | const snd_pcm_channel_area_t *dst_areas, 64 | snd_pcm_uframes_t dst_offset, 65 | const snd_pcm_channel_area_t *src_areas, 66 | snd_pcm_uframes_t src_offset, 67 | snd_pcm_uframes_t size) 68 | { 69 | snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext; 70 | short *src = area_addr(src_areas, src_offset); 71 | short *dst = area_addr(dst_areas, dst_offset); 72 | unsigned int count = size; 73 | short *databuf; 74 | 75 | if (!spx->state && !spx->echo_state) { 76 | /* no DSP processing */ 77 | memcpy(dst, src, count * 2); 78 | return size; 79 | } 80 | 81 | if (spx->echo_state) 82 | databuf = spx->outbuf; 83 | else 84 | databuf = spx->buf; 85 | 86 | while (count > 0) { 87 | unsigned int chunk; 88 | if (spx->filled + count > spx->parms.frames) 89 | chunk = spx->parms.frames - spx->filled; 90 | else 91 | chunk = count; 92 | if (spx->processed) 93 | memcpy(dst, databuf + spx->filled, chunk * 2); 94 | else 95 | memset(dst, 0, chunk * 2); 96 | dst += chunk; 97 | memcpy(spx->buf + spx->filled, src, chunk * 2); 98 | spx->filled += chunk; 99 | if (spx->filled == spx->parms.frames) { 100 | if (spx->echo_state) 101 | speex_echo_capture(spx->echo_state, spx->buf, 102 | spx->outbuf); 103 | if (spx->state) 104 | speex_preprocess_run(spx->state, databuf); 105 | if (spx->echo_state) 106 | speex_echo_playback(spx->echo_state, databuf); 107 | spx->processed = 1; 108 | spx->filled = 0; 109 | } 110 | src += chunk; 111 | count -= chunk; 112 | } 113 | 114 | return size; 115 | } 116 | 117 | static int spx_init(snd_pcm_extplug_t *ext) 118 | { 119 | snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext; 120 | 121 | spx->filled = 0; 122 | spx->processed = 0; 123 | 124 | if (!spx->buf) { 125 | spx->buf = malloc(spx->parms.frames * 2); 126 | if (!spx->buf) 127 | return -ENOMEM; 128 | } 129 | memset(spx->buf, 0, spx->parms.frames * 2); 130 | 131 | if (!spx->outbuf) { 132 | spx->outbuf = malloc(spx->parms.frames * 2); 133 | if (!spx->outbuf) 134 | return -ENOMEM; 135 | } 136 | memset(spx->outbuf, 0, spx->parms.frames * 2); 137 | 138 | if (spx->state) { 139 | speex_preprocess_state_destroy(spx->state); 140 | spx->state = NULL; 141 | } 142 | if (spx->echo_state) { 143 | speex_echo_state_destroy(spx->echo_state); 144 | spx->echo_state = NULL; 145 | } 146 | 147 | if (spx->parms.echo) { 148 | spx->echo_state = speex_echo_state_init(spx->parms.frames, 149 | spx->parms.filter_length); 150 | if (!spx->echo_state) 151 | return -EIO; 152 | speex_echo_ctl(spx->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, 153 | &spx->ext.rate); 154 | } 155 | 156 | /* no preprocessor? */ 157 | if (!spx->parms.denoise && !spx->parms.agc && !spx->parms.dereverb) 158 | return 0; 159 | 160 | spx->state = speex_preprocess_state_init(spx->parms.frames, 161 | spx->ext.rate); 162 | if (!spx->state) 163 | return -EIO; 164 | if (spx->echo_state) 165 | speex_preprocess_ctl(spx->state, 166 | SPEEX_PREPROCESS_SET_ECHO_STATE, 167 | spx->echo_state); 168 | 169 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DENOISE, 170 | &spx->parms.denoise); 171 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_AGC, 172 | &spx->parms.agc); 173 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, 174 | &spx->parms.agc_level); 175 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DEREVERB, 176 | &spx->parms.dereverb); 177 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, 178 | &spx->parms.dereverb_decay); 179 | speex_preprocess_ctl(spx->state, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, 180 | &spx->parms.dereverb_level); 181 | return 0; 182 | } 183 | 184 | static int spx_close(snd_pcm_extplug_t *ext) 185 | { 186 | snd_pcm_speex_t *spx = (snd_pcm_speex_t *)ext; 187 | free(spx->outbuf); 188 | free(spx->buf); 189 | if (spx->state) 190 | speex_preprocess_state_destroy(spx->state); 191 | if (spx->echo_state) 192 | speex_echo_state_destroy(spx->echo_state); 193 | return 0; 194 | } 195 | 196 | static const snd_pcm_extplug_callback_t speex_callback = { 197 | .transfer = spx_transfer, 198 | .init = spx_init, 199 | .close = spx_close, 200 | }; 201 | 202 | static int get_bool_parm(snd_config_t *n, const char *id, const char *str, 203 | int *val_ret) 204 | { 205 | int val; 206 | if (strcmp(id, str)) 207 | return 0; 208 | 209 | val = snd_config_get_bool(n); 210 | if (val < 0) { 211 | SNDERR("Invalid value for %s", id); 212 | return val; 213 | } 214 | *val_ret = val; 215 | return 1; 216 | } 217 | 218 | static int get_int_parm(snd_config_t *n, const char *id, const char *str, 219 | int *val_ret) 220 | { 221 | long val; 222 | int err; 223 | 224 | if (strcmp(id, str)) 225 | return 0; 226 | err = snd_config_get_integer(n, &val); 227 | if (err < 0) { 228 | SNDERR("Invalid value for %s parameter", id); 229 | return err; 230 | } 231 | *val_ret = val; 232 | return 1; 233 | } 234 | 235 | static int get_float_parm(snd_config_t *n, const char *id, const char *str, 236 | float *val_ret) 237 | { 238 | double val; 239 | int err; 240 | 241 | if (strcmp(id, str)) 242 | return 0; 243 | err = snd_config_get_ireal(n, &val); 244 | if (err < 0) { 245 | SNDERR("Invalid value for %s", id); 246 | return err; 247 | } 248 | *val_ret = val; 249 | return 1; 250 | } 251 | 252 | SND_PCM_PLUGIN_DEFINE_FUNC(speex) 253 | { 254 | snd_config_iterator_t i, next; 255 | snd_pcm_speex_t *spx; 256 | snd_config_t *sconf = NULL; 257 | int err; 258 | struct spx_parms parms = { 259 | .frames = 64, 260 | .denoise = 1, 261 | .agc = 0, 262 | .agc_level = 8000, 263 | .dereverb = 0, 264 | .dereverb_decay = 0, 265 | .dereverb_level = 0, 266 | .echo = 0, 267 | .filter_length = 256, 268 | }; 269 | 270 | snd_config_for_each(i, next, conf) { 271 | snd_config_t *n = snd_config_iterator_entry(i); 272 | const char *id; 273 | if (snd_config_get_id(n, &id) < 0) 274 | continue; 275 | if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || 276 | strcmp(id, "hint") == 0) 277 | continue; 278 | if (strcmp(id, "slave") == 0) { 279 | sconf = n; 280 | continue; 281 | } 282 | err = get_int_parm(n, id, "frames", &parms.frames); 283 | if (err) 284 | goto ok; 285 | err = get_bool_parm(n, id, "denoise", &parms.denoise); 286 | if (err) 287 | goto ok; 288 | err = get_bool_parm(n, id, "agc", &parms.agc); 289 | if (err) 290 | goto ok; 291 | err = get_float_parm(n, id, "agc_level", &parms.agc_level); 292 | if (err) 293 | goto ok; 294 | err = get_bool_parm(n, id, "dereverb", &parms.dereverb); 295 | if (err) 296 | goto ok; 297 | err = get_float_parm(n, id, "dereverb_decay", 298 | &parms.dereverb_decay); 299 | if (err) 300 | goto ok; 301 | err = get_float_parm(n, id, "dereverb_level", 302 | &parms.dereverb_level); 303 | if (err) 304 | goto ok; 305 | err = get_bool_parm(n, id, "echo", &parms.echo); 306 | if (err) 307 | goto ok; 308 | err = get_int_parm(n, id, "filter_length", 309 | &parms.filter_length); 310 | if (err) 311 | goto ok; 312 | SNDERR("Unknown field %s", id); 313 | err = -EINVAL; 314 | ok: 315 | if (err < 0) 316 | return err; 317 | } 318 | 319 | if (!sconf) { 320 | SNDERR("No slave configuration for speex pcm"); 321 | return -EINVAL; 322 | } 323 | 324 | spx = calloc(1, sizeof(*spx)); 325 | if (!spx) 326 | return -ENOMEM; 327 | 328 | spx->ext.version = SND_PCM_EXTPLUG_VERSION; 329 | spx->ext.name = "Speex DSP Plugin"; 330 | spx->ext.callback = &speex_callback; 331 | spx->ext.private_data = spx; 332 | spx->parms = parms; 333 | 334 | err = snd_pcm_extplug_create(&spx->ext, name, root, sconf, 335 | stream, mode); 336 | if (err < 0) { 337 | free(spx); 338 | return err; 339 | } 340 | 341 | snd_pcm_extplug_set_param(&spx->ext, SND_PCM_EXTPLUG_HW_CHANNELS, 1); 342 | snd_pcm_extplug_set_slave_param(&spx->ext, 343 | SND_PCM_EXTPLUG_HW_CHANNELS, 1); 344 | snd_pcm_extplug_set_param(&spx->ext, SND_PCM_EXTPLUG_HW_FORMAT, 345 | SND_PCM_FORMAT_S16); 346 | snd_pcm_extplug_set_slave_param(&spx->ext, SND_PCM_EXTPLUG_HW_FORMAT, 347 | SND_PCM_FORMAT_S16); 348 | 349 | *pcmp = spx->ext.pcm; 350 | return 0; 351 | } 352 | 353 | SND_PCM_PLUGIN_SYMBOL(speex); 354 | -------------------------------------------------------------------------------- /usb_stream/98-usb-stream.conf: -------------------------------------------------------------------------------- 1 | pcm.usbstream { 2 | @args [ CARD RATE PERIOD_SIZE ] 3 | @args.CARD { 4 | type string 5 | default { 6 | func refer 7 | name defaults.pcm.card 8 | } 9 | } 10 | @args.RATE { 11 | type integer 12 | } 13 | @args.PERIOD_SIZE { 14 | type integer 15 | } 16 | type usb_stream 17 | card $CARD 18 | rate $RATE 19 | period_size $PERIOD_SIZE 20 | hint { 21 | show { 22 | @func refer 23 | name defaults.namehint.basic 24 | } 25 | description "USB Stream Output" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /usb_stream/Makefile.am: -------------------------------------------------------------------------------- 1 | GCONF_FILES = 98-usb-stream.conf 2 | 3 | EXTRA_DIST = $(GCONF_FILES) 4 | 5 | asound_module_pcm_usb_stream_LTLIBRARIES = libasound_module_pcm_usb_stream.la 6 | asound_module_gconf_DATA = $(GCONF_FILES) 7 | 8 | asound_module_pcm_usb_streamdir = @ALSA_PLUGIN_DIR@ 9 | asound_module_gconfdir = @ALSA_GCONF_DIR@ 10 | 11 | AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ 12 | AM_LDFLAGS = -module -avoid-version -export-dynamic $(LDFLAGS_NOUNDEFINED) 13 | 14 | libasound_module_pcm_usb_stream_la_SOURCES = pcm_usb_stream.c 15 | libasound_module_pcm_usb_stream_la_LIBADD = @ALSA_LIBS@ -lpthread 16 | 17 | noinst_HEADERS = usb_stream.h 18 | 19 | include ../install-hooks.am 20 | 21 | install-data-hook: install-conf-hook 22 | 23 | uninstall-local: uninstall-conf-hook 24 | -------------------------------------------------------------------------------- /usb_stream/pcm_usb_stream.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PCM - USB_STREAM plugin 3 | * 4 | * Copyright (c) 2008, 2010 by Karsten Wiese 5 | * 6 | * This library is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #define _GNU_SOURCE 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "usb_stream.h" 34 | 35 | #define DEBUG 36 | #ifdef DEBUG 37 | #define DBG(f, ...) \ 38 | fprintf(stderr, "%s:%i %i "f"\n", __FUNCTION__, __LINE__, getpid(), ## __VA_ARGS__); 39 | #else 40 | #define DBG(f, ...) 41 | #endif 42 | 43 | #ifdef VDEBUG 44 | #define VDBG(f, ...) \ 45 | fprintf(stderr, "%s:%i %i "f"\n", __FUNCTION__, __LINE__, getpid(), ## __VA_ARGS__); 46 | #else 47 | #define VDBG(f, ...) 48 | #endif 49 | 50 | #define FRAME_SIZE 6 51 | 52 | struct user_usb_stream { 53 | int card; 54 | unsigned use; 55 | struct usb_stream *s; 56 | void *write_area; 57 | struct user_usb_stream *next; 58 | }; 59 | 60 | typedef struct { 61 | snd_pcm_ioplug_t io; 62 | 63 | snd_hwdep_t *hwdep; 64 | struct user_usb_stream *uus; 65 | 66 | struct pollfd pfd; 67 | 68 | unsigned int num_ports; 69 | unsigned periods_start; 70 | unsigned periods_done; 71 | 72 | unsigned channels; 73 | snd_pcm_uframes_t period_size; 74 | unsigned int rate; 75 | } snd_pcm_us_t; 76 | 77 | static struct user_usb_stream *uus; 78 | static pthread_mutex_t uus_mutex = PTHREAD_MUTEX_INITIALIZER; 79 | 80 | static struct user_usb_stream *get_uus(int card) 81 | { 82 | pthread_mutex_lock(&uus_mutex); 83 | 84 | struct user_usb_stream **l_uus = &uus, 85 | *r_uus = NULL; 86 | while (*l_uus) { 87 | if ((*l_uus)->card == card) { 88 | r_uus = *l_uus; 89 | r_uus->use++; 90 | goto unlock; 91 | } 92 | l_uus = &(*l_uus)->next; 93 | } 94 | r_uus = calloc(1, sizeof(*r_uus)); 95 | if (r_uus) { 96 | r_uus->use = 1; 97 | r_uus->card = card; 98 | *l_uus = r_uus; 99 | } 100 | 101 | unlock: 102 | pthread_mutex_unlock(&uus_mutex); 103 | return r_uus; 104 | } 105 | 106 | static void uus_free(snd_pcm_us_t *us) 107 | { 108 | if (!us->uus) 109 | return; 110 | 111 | pthread_mutex_lock(&uus_mutex); 112 | us->uus->use--; 113 | if (!us->uus->use) { 114 | struct user_usb_stream **n_uus = &uus, 115 | *p_uus; 116 | while (us->uus != *n_uus) { 117 | p_uus = *n_uus; 118 | n_uus = &p_uus->next; 119 | } 120 | *n_uus = us->uus->next; 121 | if (us->uus->s) { 122 | munmap(us->uus->write_area, us->uus->s->write_size); 123 | munmap(us->uus->s, us->uus->s->read_size); 124 | } 125 | free(us->uus); 126 | } 127 | pthread_mutex_unlock(&uus_mutex); 128 | } 129 | 130 | static void us_free(snd_pcm_us_t *us) 131 | { 132 | uus_free(us); 133 | free(us); 134 | } 135 | 136 | static int snd_pcm_us_close(snd_pcm_ioplug_t *io) 137 | { 138 | snd_pcm_us_t *us = io->private_data; 139 | snd_hwdep_close(us->hwdep); 140 | us_free(us); 141 | return 0; 142 | } 143 | 144 | static snd_pcm_sframes_t snd_pcm_us_pointer(snd_pcm_ioplug_t *io) 145 | { 146 | snd_pcm_us_t *us = io->private_data; 147 | struct usb_stream *s = us->uus->s; 148 | snd_pcm_sframes_t hw_pointer; 149 | 150 | switch (io->state) { 151 | case SND_PCM_STATE_RUNNING: 152 | VDBG("%u %u", s->periods_done, us->periods_done); 153 | if (s->periods_done - us->periods_done <= 1) 154 | hw_pointer = 155 | (s->periods_done - us->periods_start) & 1 ? 156 | io->period_size : 0; 157 | else 158 | hw_pointer = -EPIPE; 159 | 160 | break; 161 | case SND_PCM_STATE_XRUN: 162 | hw_pointer = -EPIPE; 163 | break; 164 | default: 165 | hw_pointer = 0; 166 | break; 167 | } 168 | VDBG("%li", hw_pointer); 169 | return hw_pointer; 170 | } 171 | 172 | static int snd_pcm_us_prepare(snd_pcm_ioplug_t *io) 173 | { 174 | struct usb_stream_config us_cfg; 175 | snd_pcm_us_t *us = io->private_data; 176 | struct user_usb_stream *uus = us->uus; 177 | int ioctl_result, err; 178 | 179 | VDBG(""); 180 | 181 | us_cfg.version = USB_STREAM_INTERFACE_VERSION; 182 | us_cfg.frame_size = FRAME_SIZE; 183 | us_cfg.sample_rate = io->rate; 184 | us_cfg.period_frames = io->period_size; 185 | 186 | ioctl_result = snd_hwdep_ioctl(us->hwdep, SNDRV_USB_STREAM_IOCTL_SET_PARAMS, &us_cfg); 187 | if (ioctl_result < 0) { 188 | perror("Couldn't configure usb_stream\n"); 189 | return ioctl_result; 190 | } 191 | 192 | if (ioctl_result && uus && uus->s) { 193 | err = munmap(uus->write_area, uus->s->write_size); 194 | if (err < 0) 195 | return -errno; 196 | err = munmap(uus->s, uus->s->read_size); 197 | if (err < 0) 198 | return -errno; 199 | uus->s = NULL; 200 | } 201 | 202 | if (!uus->s) { 203 | uus->s = mmap(NULL, sizeof(struct usb_stream), 204 | PROT_READ, 205 | MAP_SHARED, us->pfd.fd, 206 | 0); 207 | if (MAP_FAILED == uus->s) { 208 | perror("ALSA/USX2Y: mmap"); 209 | return -errno; 210 | } 211 | 212 | VDBG("%p %lx %i", uus->s, uus->s, uus->s->read_size); 213 | 214 | if (memcmp(&uus->s->cfg, &us_cfg, sizeof(us_cfg))) { 215 | perror("usb_stream Configuration error usb_stream\n"); 216 | return -EIO; 217 | } 218 | 219 | 220 | uus->s = mremap(uus->s, sizeof(struct usb_stream), uus->s->read_size, MREMAP_MAYMOVE); 221 | if (MAP_FAILED == uus->s) { 222 | perror("ALSA/USX2Y: mmap"); 223 | return -EPERM; 224 | } 225 | 226 | VDBG("%p %lx %i", uus->s, uus->s, uus->s->read_size); 227 | 228 | uus->write_area = mmap(NULL, uus->s->write_size, 229 | PROT_READ|PROT_WRITE, 230 | MAP_SHARED, us->pfd.fd, 231 | (uus->s->read_size + 4095) & ~4095); 232 | if (MAP_FAILED == uus->write_area) { 233 | perror("ALSA/USX2Y: mmap"); 234 | return -1; 235 | } 236 | VDBG("%p %i", uus->write_area, uus->s->write_size); 237 | } 238 | 239 | if (uus->s->state != usb_stream_ready) 240 | return -EIO; 241 | 242 | if (poll(&us->pfd, 1, 500000) < 0) 243 | return -errno; 244 | 245 | return 0; 246 | } 247 | 248 | static int snd_pcm_us_start(snd_pcm_ioplug_t *io) 249 | { 250 | snd_pcm_us_t *us = io->private_data; 251 | VDBG("%u", us->uus->s->periods_done); 252 | 253 | us->periods_start = us->periods_done = us->uus->s->periods_done; 254 | 255 | return 0; 256 | } 257 | 258 | static int snd_pcm_us_stop(snd_pcm_ioplug_t *io) 259 | { 260 | snd_pcm_us_t *us = io->private_data; 261 | 262 | if (!us->uus->s) 263 | return 0; 264 | 265 | VDBG("%u", us->uus->s->periods_done); 266 | if (io->stream == SND_PCM_STREAM_PLAYBACK) 267 | memset(us->uus->write_area, 0, us->uus->s->write_size); 268 | 269 | return 0; 270 | } 271 | 272 | static snd_pcm_sframes_t snd_pcm_us_write(snd_pcm_ioplug_t *io, 273 | const snd_pcm_channel_area_t *areas, 274 | snd_pcm_uframes_t offset, 275 | snd_pcm_uframes_t size) 276 | { 277 | void *playback_addr; 278 | snd_pcm_us_t *us = io->private_data; 279 | struct user_usb_stream *uus = us->uus; 280 | struct usb_stream *s = uus->s; 281 | unsigned bytes; 282 | void *src = areas->addr + offset * s->cfg.frame_size; 283 | 284 | VDBG("%li %li %i %i", offset, size, areas->first, areas->step); 285 | 286 | playback_addr = uus->write_area + s->outpacket[0].offset; 287 | memcpy(playback_addr, src, s->outpacket[0].length); 288 | bytes = size * s->cfg.frame_size; 289 | if (bytes > s->outpacket[0].length) { 290 | playback_addr = uus->write_area + s->outpacket[1].offset; 291 | memcpy(playback_addr, src + s->outpacket[0].length, 292 | bytes - s->outpacket[0].length); 293 | } 294 | us->periods_done++; 295 | return size; 296 | } 297 | 298 | static int usb_stream_read(struct user_usb_stream *uus, void *to) 299 | { 300 | struct usb_stream *s = uus->s; 301 | unsigned p = s->inpacket_split, l = 0; 302 | void *i = (void *)s + s->inpacket[p].offset + s->inpacket_split_at; 303 | unsigned il = s->inpacket[p].length - s->inpacket_split_at; 304 | 305 | do { 306 | if (l + il > s->period_size) 307 | il = s->period_size - l; 308 | memcpy(to + l, i, il); 309 | l += il; 310 | if (l >= s->period_size) 311 | break; 312 | 313 | p = (p + 1) % s->inpackets; 314 | i = (void *)s + s->inpacket[p].offset; 315 | il = s->inpacket[p].length; 316 | } while (p != s->inpacket_split); 317 | 318 | return l; 319 | } 320 | 321 | static snd_pcm_sframes_t snd_pcm_us_read(snd_pcm_ioplug_t *io, 322 | const snd_pcm_channel_area_t *areas, 323 | snd_pcm_uframes_t offset, 324 | snd_pcm_uframes_t size) 325 | { 326 | snd_pcm_us_t *us = io->private_data; 327 | unsigned frame_size = us->uus->s->cfg.frame_size; 328 | void *to = areas->addr + offset * frame_size; 329 | snd_pcm_uframes_t red; 330 | 331 | if (size) { 332 | if (size != us->uus->s->cfg.period_frames) { 333 | SNDERR("usb_stream plugin only supports period_size" 334 | " long reads, sorry"); 335 | return -EINVAL; 336 | } 337 | if (us->uus->s->periods_done - us->periods_done == 1) { 338 | red = usb_stream_read(us->uus, to) / frame_size; 339 | us->periods_done++; 340 | return red; 341 | } 342 | } else 343 | if (io->state == SND_PCM_STATE_XRUN) 344 | return -EPIPE; 345 | return 0; 346 | } 347 | 348 | static snd_pcm_ioplug_callback_t us_playback_callback = { 349 | .close = snd_pcm_us_close, 350 | .start = snd_pcm_us_start, 351 | .stop = snd_pcm_us_stop, 352 | .transfer = snd_pcm_us_write, 353 | .pointer = snd_pcm_us_pointer, 354 | .prepare = snd_pcm_us_prepare, 355 | }; 356 | static snd_pcm_ioplug_callback_t us_capture_callback = { 357 | .close = snd_pcm_us_close, 358 | .start = snd_pcm_us_start, 359 | .stop = snd_pcm_us_stop, 360 | .transfer = snd_pcm_us_read, 361 | .pointer = snd_pcm_us_pointer, 362 | .prepare = snd_pcm_us_prepare, 363 | }; 364 | 365 | #define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0])) 366 | 367 | static int us_set_hw_constraint(snd_pcm_us_t *us) 368 | { 369 | unsigned access_list[] = { 370 | SND_PCM_ACCESS_MMAP_INTERLEAVED, 371 | }; 372 | unsigned format_list[] = { 373 | SND_PCM_FORMAT_S24_3LE, 374 | }; 375 | 376 | int err; 377 | unsigned int rate_min = us->rate ? us->rate : 44100, 378 | rate_max = us->rate ? us->rate : 96000, 379 | period_bytes_min = us->period_size ? FRAME_SIZE * us->period_size : 128, 380 | period_bytes_max = us->period_size ? FRAME_SIZE * us->period_size : 64*4096; 381 | 382 | if ((err = snd_pcm_ioplug_set_param_list(&us->io, SND_PCM_IOPLUG_HW_ACCESS, 383 | ARRAY_SIZE(access_list), access_list)) < 0 || 384 | (err = snd_pcm_ioplug_set_param_list(&us->io, SND_PCM_IOPLUG_HW_FORMAT, 385 | ARRAY_SIZE(format_list), format_list)) < 0 || 386 | (err = snd_pcm_ioplug_set_param_minmax(&us->io, SND_PCM_IOPLUG_HW_CHANNELS, 387 | us->channels, us->channels)) < 0 || 388 | (err = snd_pcm_ioplug_set_param_minmax(&us->io, SND_PCM_IOPLUG_HW_RATE, 389 | rate_min, rate_max)) < 0 || 390 | (err = snd_pcm_ioplug_set_param_minmax(&us->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 391 | period_bytes_min, period_bytes_max)) < 0 || 392 | (err = snd_pcm_ioplug_set_param_minmax(&us->io, SND_PCM_IOPLUG_HW_PERIODS, 393 | 2, 2)) < 0) 394 | return err; 395 | 396 | return 0; 397 | } 398 | 399 | static int snd_pcm_us_open(snd_pcm_t **pcmp, const char *name, 400 | int card, 401 | snd_pcm_stream_t stream, int mode, 402 | snd_pcm_uframes_t period_size, 403 | unsigned int rate) 404 | { 405 | snd_pcm_us_t *us; 406 | int err; 407 | char us_name[32]; 408 | 409 | assert(pcmp); 410 | us = calloc(1, sizeof(*us)); 411 | if (!us) 412 | return -ENOMEM; 413 | 414 | if (snprintf(us_name, sizeof(us_name), "hw:%d", card) 415 | >= (int)sizeof(us_name)) { 416 | fprintf(stderr, "%s: WARNING: USB_STREAM client name '%s' truncated to %d characters, might not be unique\n", 417 | __func__, us_name, (int)strlen(us_name)); 418 | } 419 | VDBG("%i %s", stream, us_name); 420 | us->uus = get_uus(card); 421 | if (!us->uus) { 422 | free(us); 423 | return -ENOMEM; 424 | } 425 | err = snd_hwdep_open(&us->hwdep, us_name, O_RDWR); 426 | if (err < 0) { 427 | us_free(us); 428 | return err; 429 | } 430 | snd_hwdep_poll_descriptors(us->hwdep, &us->pfd, 1); 431 | 432 | us->channels = 2; 433 | us->period_size = period_size; 434 | us->rate = rate; 435 | 436 | us->io.version = SND_PCM_IOPLUG_VERSION; 437 | us->io.name = "ALSA <-> USB_STREAM PCM I/O Plugin"; 438 | us->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? 439 | &us_playback_callback : &us_capture_callback; 440 | us->io.private_data = us; 441 | us->io.mmap_rw = 0; 442 | us->io.poll_fd = us->pfd.fd; 443 | us->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; 444 | 445 | err = snd_pcm_ioplug_create(&us->io, name, stream, mode); 446 | if (err < 0) { 447 | us_free(us); 448 | return err; 449 | } 450 | 451 | err = us_set_hw_constraint(us); 452 | if (err < 0) { 453 | snd_pcm_ioplug_delete(&us->io); 454 | return err; 455 | } 456 | 457 | VDBG(""); 458 | *pcmp = us->io.pcm; 459 | 460 | return 0; 461 | } 462 | 463 | 464 | SND_PCM_PLUGIN_DEFINE_FUNC(usb_stream) 465 | { 466 | snd_config_iterator_t i, next; 467 | int err, card = -1; 468 | long period_size = 0, rate = 0; 469 | 470 | snd_config_for_each(i, next, conf) { 471 | snd_config_t *n = snd_config_iterator_entry(i); 472 | const char *id; 473 | if (snd_config_get_id(n, &id) < 0) 474 | continue; 475 | 476 | if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0 || strcmp(id, "hint") == 0) 477 | continue; 478 | if (strcmp(id, "card") == 0) { 479 | card = snd_config_get_card(n); 480 | if (card < 0) { 481 | SNDERR("Invalid card '%s'", id); 482 | return -EINVAL; 483 | } 484 | continue; 485 | } 486 | if (strcmp(id, "period_size") == 0) { 487 | if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { 488 | SNDERR("Invalid type for %s", id); 489 | return -EINVAL; 490 | } 491 | snd_config_get_integer(n, &period_size); 492 | continue; 493 | } 494 | if (strcmp(id, "rate") == 0) { 495 | if (snd_config_get_type(n) != SND_CONFIG_TYPE_INTEGER) { 496 | SNDERR("Invalid type for %s", id); 497 | return -EINVAL; 498 | } 499 | snd_config_get_integer(n, &rate); 500 | continue; 501 | } 502 | SNDERR("Unknown field %s", id); 503 | return -EINVAL; 504 | } 505 | 506 | err = snd_pcm_us_open(pcmp, name, card, stream, mode, period_size, rate); 507 | 508 | return err; 509 | } 510 | 511 | SND_PCM_PLUGIN_SYMBOL(usb_stream); 512 | -------------------------------------------------------------------------------- /usb_stream/usb_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007, 2008 Karsten Wiese 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License as published by the 6 | * Free Software Foundation; either version 2 of the License, or (at your 7 | * option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 | * for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software Foundation, 16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #define USB_STREAM_INTERFACE_VERSION 2 20 | 21 | #define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \ 22 | _IOW('H', 0x90, struct usb_stream_config) 23 | 24 | struct usb_stream_packet { 25 | unsigned offset; 26 | unsigned length; 27 | }; 28 | 29 | 30 | struct usb_stream_config { 31 | unsigned version; 32 | unsigned sample_rate; 33 | unsigned period_frames; 34 | unsigned frame_size; 35 | }; 36 | 37 | struct usb_stream { 38 | struct usb_stream_config cfg; 39 | unsigned read_size; 40 | unsigned write_size; 41 | 42 | unsigned period_size; 43 | 44 | unsigned state; 45 | 46 | int idle_insize; 47 | int idle_outsize; 48 | int sync_packet; 49 | unsigned insize_done; 50 | unsigned periods_done; 51 | unsigned periods_polled; 52 | 53 | struct usb_stream_packet outpacket[2]; 54 | unsigned inpackets; 55 | unsigned inpacket_head; 56 | unsigned inpacket_split; 57 | unsigned inpacket_split_at; 58 | unsigned next_inpacket_split; 59 | unsigned next_inpacket_split_at; 60 | struct usb_stream_packet inpacket[0]; 61 | }; 62 | 63 | enum usb_stream_state { 64 | usb_stream_invalid, 65 | usb_stream_stopped, 66 | usb_stream_sync0, 67 | usb_stream_sync1, 68 | usb_stream_ready, 69 | usb_stream_running, 70 | usb_stream_xrun, 71 | }; 72 | 73 | #if __KERNEL__ 74 | 75 | #define USB_STREAM_NURBS 4 76 | #define USB_STREAM_URBDEPTH 4 77 | 78 | struct usb_stream_kernel { 79 | struct usb_stream *s; 80 | 81 | void *write_page; 82 | 83 | unsigned n_o_ps; 84 | 85 | struct urb *inurb[USB_STREAM_NURBS]; 86 | struct urb *idle_inurb; 87 | struct urb *completed_inurb; 88 | struct urb *outurb[USB_STREAM_NURBS]; 89 | struct urb *idle_outurb; 90 | struct urb *completed_outurb; 91 | struct urb *i_urb; 92 | 93 | int iso_frame_balance; 94 | 95 | wait_queue_head_t sleep; 96 | 97 | unsigned out_phase; 98 | unsigned out_phase_peeked; 99 | unsigned freqn; 100 | }; 101 | 102 | struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk, 103 | struct usb_device *dev, 104 | unsigned in_endpoint, unsigned out_endpoint, 105 | unsigned sample_rate, unsigned use_packsize, 106 | unsigned period_frames, unsigned frame_size); 107 | void usb_stream_free(struct usb_stream_kernel *); 108 | int usb_stream_start(struct usb_stream_kernel *); 109 | void usb_stream_stop(struct usb_stream_kernel *); 110 | 111 | 112 | #endif 113 | --------------------------------------------------------------------------------